CQRS:在CommandHandlers中注入messageBus

时间:2015-05-07 09:39:11

标签: php messaging cqrs

这听起来像是在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);
   }
}

耦合不是太多了吗?

2 个答案:

答案 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);

  }

}