2017-02-01 24 views
3

В книге Vaughn Vernon's Implementing Domain-Driven Design он описал использование заводского метода в сводном корне. Примером может служить совокупный корень Forum, который имеет фабричный метод startDiscussion, который возвращает корень агрегата Discussion.Может ли метод агрегатной корневой фабрики возвращать команду вместо публикации события?

Как реализовать этот заводской шаблон в системе поиска событий, особенно в Axon?

Я считаю, что обычно, он может быть реализован следующим образом:

StartDiscussionCommand ->DiscussionStartedEvent ->CreateDiscussionCommand ->DiscussionCreatedEvent

Мы огнь StartDiscussionCommand быть обрабатываемым Forum, Forum затем публикует a DiscussionStartedEvent. Внешний обработчик событий поймал бы DiscussionStartedEvent, преобразует его и запускает CreateDiscussionCommand. Другой обработчик будет создавать экземпляр Discussion, используя CreateDiscussionCommand, а Discussion будет стрелять DiscussionCreatedEvent.

Альтернативно, мы можем вместо этого: StartDiscussionCommand ->CreateDiscussionCommand ->DiscussionCreatedEvent

Мы огонь StartDiscussionCommand, который бы вызвать обработчик команд и вызывать Forum «s startDiscussion() метод, который будет возвращать CreateDiscussionCommand. Затем обработчик отправит этот CreateDiscussionCommand. Другой обработчик получает команду и использует ее для создания экземпляра Discussion. Discussion затем запустит DiscussionCreatedEvent.

Первая практика включает в себя 4 DTO, в то время как вторая включает только 3 DTO.

Любые мысли о том, какая практика должна быть предпочтительной? Или есть другой способ сделать это?

+0

'DiscussionCreatedCommand' is' DiscussionCreatedEvent' –

+0

@ConstantinGALBENU Спасибо, что указал на клерикальную ошибку. Я исправил это. – sofiaguyang

+0

Я бы выбрал первое решение, но без 'CreateDiscussionCommand' и' DiscussionCreatedEvent'. Вам это действительно нужно? Я считаю, что 'DiscussionStartedEvent' может быть достаточно –

ответ

4

Лучшим подходом к такой проблеме является рассмотрение ваших агрегатов (фактически, всей системы) в качестве черного ящика в первую очередь. Просто посмотрите на API.

Given a Forum (that is not closed), 
When I send a StartedDiscussionCommand for that forum, 
A new Discussion is started. 

Но также

Given a Forum that was closed 
When I send a CreateDiscussionCommand for that forum, 
An exception is raised 

Обратите внимание, что API вы предложили слишком технический. В «реальной жизни» вы не создаете дискуссию, вы начинаете ее.

Это означает, что состояние форума связано с созданием обсуждения. Поэтому в идеале (при просмотре черного ящика) такой сценарий будет реализован в агрегаторе Форума и применит событие, которое представляет событие создания для совокупности обсуждений. Это делается в предположении, что другие факторы требуют, чтобы Форум и Обсуждение были двумя различными агрегатами.

Поэтому вы не хотите, чтобы обработчик команды возвращал/отправлял команду, вы хотите, чтобы этот обработчик принял решение о создании агрегата или нет.

К сожалению, Axon пока не поддерживает эту функцию. На данный момент Axon не может применять событие, принадлежащее другому агрегату, через его обычные API.

Однако, есть способ сделать это. В Axon 3 вам не нужно apply Событие, вы также можете публиковать его непосредственно на шине событий (что в случае Event Sourcing будет реализацией магазина событий). Таким образом, чтобы реализовать это, вы можете напрямую опубликовать DomainEventMessage, который содержит DiscussionCreatedEvent. Идентификатором для обсуждения может быть любой UUID, а порядковый номер события равен 0, поскольку это событие создания обсуждения.

+0

Вы хотите сказать, что я должен вставить EventStore в корневой узел 'Forum'? – sofiaguyang

+0

У меня есть идея, как я могу это сделать. Спасибо за понимание. Я скоро дам обновление. – sofiaguyang

+0

Прошу прощения, потребовалось некоторое время, но да, мне удалось сделать ваше предложение. Благодаря! – sofiaguyang

-1

Любые мысли о том, какая практика должна быть предпочтительной?

Мотивация команды заключается в том, чтобы направить приложение на обновление книги записи. Команда, которую вы не ожидаете произвести событие, довольно странная.

То есть, если ваш поток

Forum.startDiscussion -> [] 
Discussion.create -> [ DiscussionCreated ] 

Один обязан спросить, почему Форум участвует на всех?

if (this.isClosed()) { 
    throw new IllegalStateException("Forum is closed."); 
} 

Это здесь есть иллюзия - мы смотрим на состояние Форума в некоторой произвольной точке в прошлом, чтобы обработать команду для обсуждения. Другими словами, после этой проверки состояние Forum могло измениться, и наша обработка в Обсуждение не знала. Поэтому было бы правильно сделать эту проверку при проверке команды или путем проверки модели чтения из обсуждения.

(Все, что мы получаем из книжной книги, представляет собой представление о прошлом, оно должно быть, чтобы быть в книге записей для нас, чтобы читать. Единственный момент, когда мы действуем в настоящем, этот момент, когда мы обновляем книгу записей. Точнее, ее в момент написания мы обнаруживаем, что предположения, которые мы сделали о прошлом, сохраняются. Когда мы пишем изменения в «Обсуждение», мы доказываем, что обсуждение hasn изменилось с тех пор, как мы читаем данные, но это ничего не говорит о том, изменился ли Форум).

Какая команда command-> выглядит как адаптер совместимости api; в старом API мы использовали команду Forum.startDiscussion. Мы изменили модель, но продолжаем поддерживать старую команду для обратной совместимости. Все это было бы синхронно с запросом.

Это настоящая вещь (мы хотим, чтобы дизайн поддерживал агрессивные обновления модели, не требуя постоянного обновления клиентов/потребителей), но это не подходит для вашего потока процессов.

+0

Внимательно прочитайте код: 'throw new IllegalStateException (« Форум закрыт. »);' –

 Смежные вопросы

  • Нет связанных вопросов^_^