理解领域驱动设计 (5)

在应用服务中,通过调用聚合及领域服务,完成这一创建 Invoice 的用例。

[UnitOfWork] [Authorize(PermissionNames.Invoice_Create)] public async Task CreateInvoice(CreateInvoiceDto input) { await _invoiceManager.ValidCheck(input.orderId, input.SupplierId);     var invoice = Invoice.Create(input.Name, input.Description)         .SetOrder(input.OrderId); await _invoiceManager.SetFinanceMonth(invoice, input.SupplierId);     await _invoiceRepository.InsertAsync(invoice);     await _appNotifier.NewInvoiceAsync(); }

借助领域服务,以此来完成多聚合间的协作,通过应用服务编排领域模型对象,完成一个业务用例。

领域事件

在软件开发中,事件早已被我们所熟悉,一个按钮按下,产生中断事件,一个回车,前端页面有侦听事件,在事件风暴建模活动中,事件也是作为领域建模的突破口,事件的重要性不言而喻。其本质是发生的事实到引发了相关事情,在这其中的传递的信息便是事件的内容。就如同猫叫了,引发着老鼠跑了,主人醒了,其中的事件便是猫叫了,而该事件是猫执行叫的动作后的结果。

在领域驱动设计中,最开始的版本中并没有领域事件的概念,在 DDD 社区对领域驱动设计的内容不断的充实中,引入了领域事件。领域事件的命名遵循英语中的“名词 + 动词过去分词”格式,如,提交订单后发布的 OrderCreated 事件,订单完成后 OrderCompleted 事件,用以表示我们建模的领域中发生过的一件事情,也符合着事件本身是具有时间特征。

图片

(EShopOnContainers 中一个例子)

对于领域事件本身,依据各层的使用方式及面对的目标不同,划分出两种事件类型,领域事件与应用事件(或集成事件),应用事件侧重于应用层的使用,而领域事件沿用原领域事件的称呼,更偏向于领域层。而又应侧重点不同,又有着不同的使用方式,如领域事件更多的是从领域模型中发布,其最终接收者为当前聚合所在限界上下文,而应用事件更为广阔,从应用层发布,其接收者为当前上下文或是其他上下文。

基于限界上下文间采用的部署方式不同,也存在着不同的通信方式,如整个应用程序为单体,则所有上下文在同一个进程内,则上下文间事件交互时所采用的可以是进程内的事件总线,或是进程间使用的消息队列,而当在进程间时,就不得不使用进程间的消息队列了。

由于 DDD 中遵循一个用例对应一个事务,在一个事务中更新一个聚合,因此对于实际场景中需要变更多个聚合下,我们常通过编排方式调用其他聚合的服务,这不可避免的加重了对其他服务的依赖,借助领域事件,则可以很方便的降低这种耦合,同时对于多个聚合的变更操作,由单个聚合的事务变成了多个聚合的事务,又依照实际影响的聚合情况,有着不同的处理方式,如多个协作的聚合为同一上下文内时,可通过强一致性去保证数据一致性,而处于多个限界上下文间的聚合时,则可依照最终一致性保证数据的一致性。

领域事件主要用途有:

从事件角度丰富了领域模型

保证聚合间的数据一致性

实现事件事件溯源和 CQRS 等

限界上下文间集成(发布订阅模式)

资源库

在刚接触资源库(Repository)时,第一反应便是这就是个 DAO 层,访问数据库,然后吧啦吧啦,但是,当接触的越久,越发认识到第一反应是错的,资源库更多的是对资源的管理,而不仅仅是数据库中的数据,数据库可以作为资源的一部分,但不是全部,我们习惯将对外部系统的调用称为外部资源的获取,这也是将外部系统作为资源的一部分。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzfwj.html