1、引言
继领域服务之后继续学习领域事件,那么我们要知道领域事件的作用又是什么?为什么要使用领域事件?
领域专家所关心的发生在领域中的一些事件。将领域中所发生的活动建模成一系列的离散事件。每个事件都用领域对象来表示...领域事件是领域模型的组成部分,表示领域中所发生的事情。
当领域事件确定下来时,领域事件便是通用语言的正式组成部分。
2、了解领域事件
一个领域事件可以理解为是发生在一个特定领域中的事件,是你希望在同一个领域中其他部分知道并产生后续动作的事件。但是并不是所有发生过的事情都可以成为领域事件。一个领域事件必须对业务有价值,有助于形成完整的业务闭环,也即一个领域事件将导致进一步的业务操作。
领域事件可以是业务流程的一个步骤,例如订单提交,客户付费100元,订单完成等。领域事件也可以是定时发生的事情,例如每晚对账完成。或者是一个事件发生后引发的后续动作,例如客户输错密码三次后发生锁定账户的事件。
如果在通用语言中存在“当a发生时,我们就需要做到b。”这样的描述,则表明a可以定义成一个领域事件。领域事件的命名一般也就是“产生事件的对象名称+完成的动作的过去式”的形式,比如:订单已经发货的事件(OrderDispatchedEvent)、订单已被收货和确认的事件(OrderConfirmedEvent)等。
如何实现支付订单成功,更新订单状态为已支付,扣减库存,并推送捡货通知信息到捡货中心。传统思想肯定是简单直接的方法调用,在一个事务中分别去调用状态更新方法、扣减库存方法、发送捡货通知方法。
那这样设计有问题吗?
试想一下,若现在要求支付成功后,需要额外发送一条付款成功通知到微信公众号,怎么实现?想必我们需要额外定义发送微信通知的接口并封装参数,然后再添加对方法的调用。这种做法虽然可以解决需求的变更,但很显然不够灵活耦合性强,也违反了OCP。
OCP Open-Closed Principle软件设计中的“开-闭原则”,一个软件实体应当对扩展开放,对修改关闭.也就是说,我们在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展,换句话说就是,应当可以在不必修改源代码的情况下改变这个模块的行为.
将多个操作放在同一个事务中,使用事务一致性可以保证多个操作要么全部成功要么全部失败。在一个事务中处理多个操作,若其中一个操作失败,则全部失败。但是,这在业务上是不允许的。客户成功支付了,却发现订单依旧为待付款,这会导致纠纷的。
违反了聚合的一大原则:在一个事务中,只对一个聚合进行修改。在这个用例中,很明显我们在一个事务中对订单聚合和库存聚合进行了修改。
那如何解决这些问题?我们可以借助领域事件的力量。
3、为什么需要领域事件
上面所举的例子,按照传统的方式去开发,会导致系统高耦合。
如果改为事件驱动模式,把订单提交后触发一个事件,在订单保存后,触发订单提交事件。通知和后续的各种服务动作可以通过订阅这个事件,在自己的实现空间内实现对应的逻辑,这样就把订单提交和后续其他非主要活动从订单提交业务中剥离,实现了订单提交业务高内聚和低耦合性和系统可扩展性。
4、小结
上一章说到领域服务处理业务,比较容易代码耦合,领域事件解耦,所以可以确定的是领域事件是领域服务中重要的组成部分。并且我们要知道,领域事件是用来处理已经发生的事情,比如订单状态改变后,商品添加到购物车后这类事件。而且不是所有的事件都要建模领域事件,只有有价值的业务才建模领域事件。领域事件是需要跟踪的、希望被通知的、会引起其他模型对象改变状态的,发生在领域中的一些事情。