在强调事件的体系结构中,命令和事件之间有什么区别?我能看到的唯一区别是命令通常是由系统外部的参与者来发起/调用的,而事件似乎是由系统中的处理程序和其他代码来发起的。但是,在我看到的许多示例应用程序中,它们具有不同(但功能相似)的接口。
在强调事件的体系结构中,命令和事件之间有什么区别?我能看到的唯一区别是命令通常是由系统外部的参与者来发起/调用的,而事件似乎是由系统中的处理程序和其他代码来发起的。但是,在我看到的许多示例应用程序中,它们具有不同(但功能相似)的接口。
Answers:
命令可以被拒绝。
事件发生了。
这可能是最重要的原因。在事件驱动的体系结构中,毫无疑问,引发的事件表示已经发生的事情。
现在,由于命令是我们想要发生的事情,而事件是已经发生的事情,因此在命名这些事物时,我们应该使用不同的动词。这将驱动单独的表示。
我可以看到的是,命令通常是由系统外部的参与者来发起/调用的,而事件似乎是由系统中的处理程序和其他代码来发起的
这是它们分别表示的另一个原因。概念清晰。
命令和事件都是消息。但是它们实际上是独立的概念,应该对概念进行显式建模。
另外,除了此处公开的所有答案之外,事件处理程序在接收到事件发生的通知后也可能能够触发命令。
举例来说,创建客户后,您还想初始化一些帐户值,等等。在客户AR将事件添加到EventDispatcher并由CustomerCreatedEventHandler对象接收到之后,此处理程序可以触发命令的调度,将执行您需要的任何内容,等等。
此外,还有DomainEvents和ApplicationEvents。区别仅仅是概念上的。您想首先分派所有域事件(其中一些事件可能会产生应用程序事件)。我是什么意思
在发生CustomerCreatedEvent之后初始化帐户是DOMAIN事件。向客户发送电子邮件通知是一个应用程序事件。
您不应该混合使用它们的原因很明显。如果您的SMTP服务器暂时关闭,这并不意味着您的DOMAIN OPERATION应该会受到影响。您仍然希望保持聚合的未损坏状态。
我通常在“聚合根”级别将事件添加到我的Dispatcher。此事件是DomainEvents或ApplicationEvents。可以是两者,也可以是很多。一旦我的命令处理程序完成,并且我回到堆栈中执行命令处理程序的代码,然后检查我的Dispatcher并分派任何其他DomainEvent。如果所有这些都成功,那么我将关闭交易。
如果我有任何应用程序事件,这是分发它们的时间。发送电子邮件不一定需要打开数据库连接,也不需要打开事务作用域。
我偏离了最初的问题,但对您来说,了解事件在概念上也可能会有所不同也很重要。
然后您有Sagas ....但是这个问题的范围有WAYYYY OFF :)
是否有意义?
在研究了一些示例,特别是Greg Young的演示文稿(http://www.youtube.com/watch?v=JHGkaShoyNs)之后,我得出的结论是命令是多余的。它们只是您用户的事件,他们确实按下了该按钮。您应该以与其他事件完全相同的方式存储它们,因为它们是数据,并且您不知道是否要在将来的视图中使用它。您的用户确实添加了商品,然后再将其从购物篮中删除,或者至少尝试这样做。您以后可能要使用此信息来提醒用户此事。
之所以分开代表,是因为它们代表了截然不同的事物。正如@qstarin所说,命令是可以被拒绝的消息,成功后将产生一个事件。命令和事件是Dto,它们是消息,在创建和实体时它们看起来很相似,但是从那时起,不一定。
如果您担心重用,则可以使用命令和事件作为(消息)有效负载的信封
class CreateSomethingCommand
{
public int CommandId {get; set;}
public SomethingEnvelope {get; set;}
}
但是,我想知道的是您为什么问:D,即您是否有太多的命令/事件?
您不能基于命令重新计算状态,因为一般而言,每次处理命令时它们都会产生不同的结果。
例如,想象一个GenerateRandomNumber
命令。每次调用它时,都会产生一个不同的随机数X。因此,如果您的状态依赖于此数字,则每次您从命令历史记录中重新计算状态时,都会得到一个不同的状态。
事件解决了这个问题。执行命令时,它会产生一系列事件,这些事件代表命令执行的结果。例如,该GenerateRandomNumber
命令可能会产生一个GeneratedNumber(X)
记录生成的随机数的事件。现在,如果您从事件日志中重新计算状态,则将始终获得相同的状态,因为您将始终使用由特定命令执行生成的相同数字。
换句话说,命令是具有副作用的功能,事件记录命令的特定执行的结果。
注意:您仍然可以记录命令的历史记录,以进行审计或调试。关键是要重新计算状态,请使用事件的历史记录,而不是命令的历史记录。
只是为了添加这些出色的答案。我想指出耦合方面的差异。
命令被定向到特定的处理器。因此,与命令启动器和处理器之间存在某种程度的依赖/耦合。
例如,UserService
创建新用户时,a将向其发送“发送电子邮件”命令EmailService
。
UserService
知道它需要的事实,EmailService
已经在耦合。如果EmailService
更改其API模式或出现故障,则将直接影响该UserService
功能。
事件不针对任何特定的事件处理程序。因此,事件发布者变得松散耦合。它不在乎什么服务消耗了它的事件。拥有0个事件使用者甚至是有效的。
例如,UserService
创建新用户时,a将发布“用户创建的事件”。可能EmailService
会消耗该事件并向用户发送电子邮件。
在这里UserService
不知道EmailService
。它们是完全分离的。如果EmailService
出现问题或更改了业务规则,我们只需要编辑EmailService
两种方法都有优点。纯粹的事件驱动架构设计很难跟踪,因为它耦合得太松散,尤其是在大型系统上。与Command重型架构的耦合程度很高。因此,理想的平衡是理想的。
希望有道理。