Всем привет.
Упражняюсь в ООП с DDD подходом на простом примере. Допустим, у нас есть в саду есть кран для полива грядок. Попытаемся смоделировать его работу. Итак, кран может быть открыт и закрыт. Пусть у нас будет агрегат
Tap
class Tap {
// ... id и другие свойства опущены
public function open() { // Emit TapOpened event }
public function close() { // Emit TapClosed event }
}
class TapOpened extends DomainEvent {
// tapId и другие свойства
}
class TapClosed extends DomainEvent {
// tapId и другие свойства
}
Теперь усложняем задачу - мы не хотим стоять целый час у крана и ждать, пока польются грядки. Мы хотим настроить автоматическое выключение (для простоты) крана по таймеру. В реализации крана ничего не меняется. В качестве таймера мы используем внешний сервис
TimerService, который можно попросить выбросить событие
TimerCreated и
TimerTimeout в нужное время. Клиентов у этого сервиса может быть много, поэтому событие
TimerTimeout он выбрасывает одно на всех:
interface TimerService {
public function windUp(period): TimerIdentity;
}
class TimerCreated extends DomainEvent {
// timerId и другие свойства
}
class TimerTimeout extends DomainEvent {
// timerId и другие свойства
}
Для активации такого усовершенствованного крана используем сервис
TapAutoCloser
class TapAutoCloser {
private timeService;
public function openTapFor(tap, period) {
tap.open();
timer = timeService->windUp(period);
//...
}
public function timeoutHandler(timerTimeoutEvent) {
// ..
tap.close()
// ..
}
}
Я опустил моменты, где по событию таймаута находится сам закрываемый кран.
Далее, собственно, вопрос. Допустим, за пять минут до автоматического закрытия крана должна включиться сирена.
Сначала я полагал, что это задача контекста крана, создать событие типа
LessThan5MinutesRemainedToTapAutoclose, которое будет ловить контекст сирены. Но поразмыслил и решил, что если в будущем добавится ещё условия, например, включить свет за полчаса до конца полива, то это опять потребует модификаций контекста крана, который ничего не знает о времени своей работы. Да и вообще, он не может знать, что ещё захотят от него другие контексты. Выходит, время должны "понимать" контексты сирены и освещения.
Но чтобы они могли рассчитать своё состояние сами, они должны знать, когда кран запланирован к закрытию. А в нашем случае контекст крана сообщает только, что он открыт (TapOpened), но ничего не говорит о том, когда он будет закрыт (ведь он и не знает). Где в этой схеме передать знание о времени работы крана через события в другие контексты?
Мне видится только один вариант - сервис таймера знает о наличии крана и вместо обезличенных
TimerCreated и
TimerTimeout будет выбрасывать что то типа
TapAutocloseTimerCreated и
TapAutocloseTimerTimeout. Но тогда сервис таймера выходит узконаправленным. А если теперь и свет надо будет включать по таймеру, то неужели для этого создавать свой таймер. Будет
TapCloseTimer и
LightSwitchTimer и т.д.? Или же их как то можно объединить?