为什么分别表示命令和事件?

alp*_*ogg 65 events command event-driven-design cqrs

强调事件的体系结构中的命令和事件之间有什么区别?我能看到的唯一区别是命令通常由系统外的actor来源/调用,而事件似乎是由处理程序和系统中的其他代码提供的.但是,在我看到的许多示例应用程序中,它们具有不同(但功能相似)的接口.

que*_*rin 139

命令可以被拒绝.

事件已经发生.

这可能是最重要的原因.在事件驱动的体系结构中,毫无疑问,引发的事件代表了已发生的事情.

现在,因为命令是我们想要发生的事情,并且事件已经发生了,所以当我们命名这些事情时,我们应该使用不同的动词.这会驱动单独的表示.

我可以看到,命令通常由系统外的actor来源/调用,而事件似乎是由处理程序和系统中的其他代码提供的.

这是他们分开代表的另一个原因.概念清晰度.

命令和事件都是消息.但它们实际上是独立的概念,应该明确地对概念进行建模.

  • 是的,我主要是在调度时说.命令被分派到单个处理程序,但事件被分派到多个侦听器.当然,实现差异在于总线,但我仍然使用单独的事件和命令接口,因此每个总线只接收它可以的消息. (7认同)
  • 使用命令,您可以使用"发送"一词(您关心此操作的目标),而使用"发布"的事件(您不关心另一端是谁). (5认同)
  • @ quentin-starin我知道这已经老了,但是我希望我可以像10次一样回答你的答案......我正要沿着"为什么不是一切都是事件,其中一些只是采取行动"的路线走下去 - 例如"SomethingRequested"然后"SomethingHappened" (3认同)

Ali*_*yat 11

事件是过去的事实。

命令只是一个请求,因此可能会被拒绝。

命令的一个重要特性是它应该只被一个接收器处理一次。这是因为命令是您要在应用程序中执行的单个操作或事务。例如,不应多次处理同一个订单创建命令。这是命令和事件之间的重要区别。事件可能会被多次处理,因为许多系统或微服务可能对事件感兴趣。'msdn'


小智 8

在研究了一些示例,尤其是 Greg Young 演示文稿 ( http://www.youtube.com/watch?v=JHGkaShoyNs ) 之后,我得出的结论是命令是多余的。它们只是来自您的用户的事件,他们确实按下了那个按钮。您应该以与其他事件完全相同的方式存储它们,因为它是数据,您不知道是否要在将来的视图中使用它。您的用户确实添加了该项目,然后从篮子中删除了该项目,或者至少尝试这样做。您稍后可能希望使用此信息来提醒用户以后注意这一点。

  • 在考虑最严格的实现时,更容易区分命令和事件:事件溯源。在这里,事件是真相的唯一来源。您可以随时通过仅重播事件来构建完整状态。相反,命令是_可能_导致事件但也可能被拒绝的请求。对于重建状态命令并不重要。因此,如果您的系统无法处理命令(例如,由于验证错误),那也没关系。如果您的系统无法处理事件,您的状态将被破坏。 (7认同)
  • 命令将本地事件与远程操作分离。在您的示例中, UserPressedButton 事件的使用者不会对 UserSelectedMenu 或 ScriptDidSomething 做出反应,除非它也知道这些事情。此外,命令通常是针对特定消费者的;同样,在您的示例中, UserPressedButton 事件的使用者无法判断用户是否选中了“确认”复选框,除非我们添加更多耦合。对于命令,所采取的行动可能取决于发送者的状态甚至外部策略。仅凭事件,这几乎是不可能的。 (2认同)

Pep*_*dez 5

另外,除了此处公开的所有答案之外,事件处理程序在接收到事件发生的通知后也可能能够触发命令。

举例来说,创建客户后,您还想初始化一些帐户值,等等。在客户AR将事件添加到EventDispatcher并由CustomerCreatedEventHandler对象接收到之后,此处理程序可以触发命令的分派将执行您需要的任何东西,等等。

另外,还有DomainEvents和ApplicationEvents。区别仅仅是概念上的。您想首先分派所有域事件(其中一些事件可能会产生应用程序事件)。我是什么意思

在发生CustomerCreatedEvent之后初始化帐户是DOMAIN事件。向客户发送电子邮件通知是一个应用程序事件。

您不应该混合使用它们的原因很明显。如果您的SMTP服务器暂时关闭,那并不意味着您的DOMAIN OPERATION应该会受到影响。您仍然希望保持聚合的未损坏状态。

我通常在“聚合根”级别将事件添加到我的调度程序。此事件是DomainEvents或ApplicationEvents。可以是两者,也可以是很多。完成命令处理程序后,我又回到堆栈中执行命令处理程序的代码,然后检查我的Dispatcher并分派其他任何DomainEvent。如果所有这些都成功,那么我将关闭交易。

如果我有任何应用程序事件,这是分发它们的时间。发送电子邮件不一定需要打开数据库连接,也不需要打开事务作用域。

我偏离了最初的问题,但对您来说,了解事件在概念上也可能会有所不同也很重要。

然后您有了Sagas ....但是这个问题的范围有WAYYYY OFF :)

是否有意义?


fro*_*roi 5

只是为了补充这些精彩的答案。我想指出耦合方面的差异。

命令针对特定处理器。因此,命令发起者和处理器之间存在一定程度的依赖/耦合。

例如,UserService在创建新用户时,将“发送电子邮件”命令发送到EmailService.

事实上, 知道UserService它需要EmailService,这已经是耦合了。如果EmailService更改其 API 架构或出现故障,则会直接影响UserService功能。


事件不针对任何特定的事件处理程序。因此,事件发布者变得松散耦合。它不关心什么服务消耗其事件。事件的 0 个消费者甚至是有效的。

例如,UserService在创建新用户时发布“用户创建事件”。可能EmailService可以使用该事件并向用户发送电子邮件。

这里UserService是不知道的EmailService。他们是完全脱钩的。如果EmailService出现故障,或者业务规则发生变化,我们只需要编辑EmailService


两种方法各有优点。纯粹的事件驱动架构设计更难跟踪,因为它的耦合过于松散,尤其是在大型系统上。而命令重架构具有高耦合度。因此,良好的平衡是理想的。

希望这是有道理的。