Action On DDD
常见的开发方式
MVC贫血模型
最常见的开发模式传统EJB开发时提倡的开发模式,是通过算法调用数据对象的getter/setter方法修改数据,再将数据存储起来的过程。
在MVC下,常见的模式是controller层中通过一部分算法判断数据对象的数据是否符合业务需要,在service中通过另一部分算法按照规则业务规则修改数据分别调用不同dao将数据更新或存储起来。
优点:
简单逻辑场景开发快,实现简单。
服务化后通信时传送的对象简洁高效
缺点:
复杂逻辑场景下,代码冗长难懂,维护困难。
代码逻辑和业务逻辑的直接关联度低,在没有注释的情况下其它人很难通过代码了解业务场景。
代码耦合度很高,难以避免出现“上帝类”的情况。
评价:
数据喂机器的开发方式,特别适合有大量表单录入的系统,对业务逻辑的表现能力差,复杂业务场景维护困难。
关于领域驱动实现的方式
核心点:领域驱动是将业务功能限制在特定领域进行划分后,专注于某些特定领域的开发方式,它的最佳实现是领域自治,即领域内的对象(聚合根)自身仅能管理自己的数据和状态,这样避免了领域对象相互污染的情况。领域驱动关心的是领域对象是什么,而不是对象做什么。
例如:转账行为中,领域关注的核心概念是 “账户(Account)”,而不是日志,但是根据业务需求需要在转账进行的过程中写入日志。为了完成业务需要,我们在账户金额变动的过程中不得不加入日志写入的行为逻辑:
class Account{
AccountLog accountLog;
// 方法内不得不集成了日志写入操作
void reduce(BigDecimal amount){
//...
accountLog.writeReduceLog(accountId,amount);
//...
}
}
我们发现,为了执行一个与领域内无关的操作,不得为了业务需要引入一个领域外的对象,导致Account对象领域被污染。
DCI
DCI是数据Data 场景Context 交互Interactions的简称,DCI是一种特别关注行为的模式(可以对应GoF行为模式),由MVC模式提出者Trygve Reenskaug提出。
Trygve Reenskaug认为数据Data应当是静态的,即数据本身不能有动作(你见过表格自己填写自己的吗?),但是数据反应了一个对象的状态。
如果要想让数据能够执行各种行为则需要将数据放入角色模型(Role Model)中,由角色模型驱动完成数据变更 (假设PersonData反应了一个人的基本信息,则如果想让这个人去工作,则必须将PersonData 放入Worker角色中)。
协作交互模型(Collaboration Model)则是驱动角色模型如何动作的关键,如果我们需要角色们协调起来去完成某个业务场景,则必须通过协作交互模型来进行(上个例子提到的Worker,如果需要执行放款操作,则还需要与对应的Account角色进行交互)。
对于DCI实现的领域驱动设计,Role和Collaboration(即Interactions)才是真正的领域模型,Context和Data则更面向于程序,由Context准备好足够的程序组件和Data,让数据通过协作模型和角色模型完成一系列动作,再将得到的Data进行存储的。
评价:
与传统Evans提倡的DDD模型略有不同,Evans提倡领域自治,即模型的数据由自己更新,DCI则是将数据分离更新。在实践过程中,DCI架构更像是一个完整的场景剧的表演过程,由Context为角色Role准备表演的“舞台”,舞台中包括了各种各样的必要设施,角色们只要根据剧本Collaboration进行表演即可,最后得到的数据是角色本身的完结状态。
CQRS
命令查询的责任分离Command Query Responsibility Segregation (简称CQRS)模式是一种架构体系模式,能够使改变模型的状态的命令和模型状态的查询实现分离。
当一个Command进来时,从仓储Repository加载一个聚合aggregate对象群,然后执行其方法和行为。这样,会激发聚合对象群产生一个事件,这个事件可以分发给仓储Repository,或者分发给Event Bus事件总线,比如JavaEE的消息总线等等。事件总线将再次激活所有监听本事件的处理者。当然一些处理者会执行其他聚合对象群的操作,包括数据库的更新。
查询时,则通过查询优化的数据库直接进行查询(典型的有将数据冗余在搜索引擎中查询或直接生成报表在数据库查询)
评价:
该架构的较为复杂,在实现起来也较为困难(特别在Spring框架下),由于数据的存储和更新都是通过事件进行,在整个系统中会出现大量不同类型的事件,在实现过程服务化的情况下,要保证游离在领域对象中的数据与数据库中的数据一致,不得不进行锁处理,不太适合传统的服务化和微服务化架构 。适合该模式开发的典型框架是Akka Actor,这是由于在Akka集群中,领域对象(Actor)由且仅有一个,不会因为并发出现多个相同的Actor。