这听起来像是在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 :(得分:2)
我甚至会说这是推荐的,因为在你的命令处理程序中,你很可能会想要回复具有处理状态的发起者,唯一的方法就是使用总线回复/响应功能。
正如在DDD / CRQS Google小组中所讨论的那样,没有“单向(或”发射并忘记“)命令”因为命令意味着动作,状态改变,这可能会失败,离开系统处于未定义状态,如果失败处理不当,则与幂等的查询进行比较。
答案 1 :(得分:1)
只要你能控制住东西;比如使用依赖注入框架或(不是过度使用)服务定位器;我认为可以将总线注入域服务。
关于拥有存储库......如何添加另一层只是为了让域服务保持持久性无知?
我的意思是,如果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);
}
}