CQRS: внедрение messageBus в CommandHandlers

Это звучит как правильный подход к залить весь автобус в commandHandlers чтобы последний мог позвонить $this->messageBus->dispatch($events);

class OneCommandHandler
{
private $messageBus;

//.....

public function handle(Command $command)
{
//..... will at some points hopefully returns DomainEvents
}

private function dispatch(DomainEvents $events)
{
$this->messageBus->dispatch($events);
}
}

Не слишком ли много связи?

0

Решение

Я бы даже сказал, что это рекомендуется, поскольку в вашем обработчике команд вы, скорее всего, захотите ответить отправителю со статусом обработки, и единственный способ сделать это — задействовать функцию ответа / ответа шины.

Как обсуждалось в группе Google DDD / CRQS, не существует такой вещи, как «команды в одну сторону (или« запустить и забыть »)», поскольку команда означает действие, изменение состояния, и это может привести к сбою, оставляя систему в неопределенном состоянии. если ошибка не обрабатывается должным образом, по сравнению с запросом, который идемпотентен.

2

Другие решения

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

О наличии хранилища … Как насчет добавления еще одного слоя, чтобы сохранить доменные службы в постоянном невежестве?

Я имею в виду, что если OneCommandHandler должен применять правила домена и инициировать события домена, тогда он относится к уровню доменных служб. Домен не должен иметь зависимостей. Домен должен применять правила и инварианты и координировать операции агрегатов. Все это должны быть входные параметры операций Домена. Возможно, вам нужен прикладной сервисный уровень в качестве координатора сервисов приложений (безопасность, ведение журналов, постоянство и т. Д.) И доменных сервисов.

т.е .:

class ProductApplicationService
{
function ProductNameExchange($productExchangeComand){

LoggingAppService.LogAction("User ask to exchange product names");
SecurityAppService.AuthorizeCommand($productExchangeComand);
$productAggregate1 = ProductRepository.getProductById($productExchangeComand.firsProductId);
$productAggregate2 = ProductRepository.getProductById($productExchangeComand.secondProductId);

//rules and invariants
ProductDomainService.ExchangeNames($productAggregate1, $productAggregate2);

}
}

class ProductDomainService{

function ExchangeNames($productAggregate1, $productAggregate2)(){
//code to coordinate the 2 aggregates
$aux = $productAggregate1.name;
$productAggregate1.setName($productAggregate2.name); //$productAggregate has its own rules to change its name
$productAggregate2.setName($aux);

}

}
1

По вопросам рекламы [email protected]