领域驱动设计
更新日期:
读文章<<领域驱动设计(DDD:Domain-Driven Design)>> Eric Evans的“Domain-Driven Design领域驱动设计”简称DDD
服务器后端发展三个阶段
UI+DataBase的两层架构,这种面向数据库的架构(上图table module )没有灵活性。
UI+Service+DataBase的多层SOA架构,这种服务+表模型的架构易使服务变得囊肿,难于维护拓展,伸缩性能差,见这里讨论或Spring Web 应用的最大败笔.The Biggest Flaw of Spring Web Applications | Java 真是败笔吗? I do not think so.
DDD+SOA的事件驱动的CQRS读写分离架构,应付复杂业务逻辑,以聚合模型替代数据表模型,以并发的事件驱动替代串联的消息驱动。真正实现以业务实体为核心的灵活拓展。
四个编程模型
失血模型 失血模型简单来说,就是domain object只有属性的getter/setter方法的纯数据类,所有的业务逻辑完全由business object来完成(又称 TransactionScript),这种模型下的domain object被Martin Fowler称之为“贫血的domain object”。
贫血模型 简单来说,就是domain ojbect包含了不依赖于持久化的领域逻辑,而那些依赖持久化的领域逻辑被分离到Service层。 Service(业务逻辑,事务封装) --> DAO ---> domain object
1 2 3 4 5 6 | 这种模型的优点: 1、各层单向依赖,结构清楚,易于实现和维护 2、设计简单易行,底层模型非常稳定 这种模型的缺点: 1、domain object的部分比较紧密依赖的持久化domain logic被分离到Service层,显得不够OO 2、Service层过于厚重 |
充血模型 充血模型和第二种模型差不多,所不同的就是如何划分业务逻辑,即认为,绝大多业务逻辑都应该被放在domain object里面(包括持久化逻辑) ,而Service层应该是很薄的一层,仅仅封装事务和少量逻辑,不和DAO层打交道。 Service(事务封装) ---> domain object <---> DAO
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 这种模型的优点: 1、更加符合OO的原则 2、Service层很薄,只充当Facade的角色,不和DAO打交道。 这种模型的缺点: 1、DAO和domain object形成了双向依赖,复杂的双向依赖会导致很多潜在的问题。 2、如何划分Service层逻辑和domain层逻辑是非常含混的,在实际项目中,由于设计和开发人员的水平差异,可能导致整个结构的混乱无序。 3、考虑到Service层的事务封装特性,Service层必须对所有的domain object的逻辑提供相应的事务封装方法,其结果就是Service完全重定义 一遍所有的domain logic,非常烦琐,而且Service的事务化封装其意义就等于把OO的domain logic转换为过程的Service TransactionScript 。该充血模型辛辛苦苦在domain层实现的OO在Service层又变成了过程式,对于Web层程序员的角度来看,和贫血模型没有什么区别了。 1.事务我是不希望由Item管理的,而是由容器或更高一层的业务类来管理。 2.如果Item不脱离持久层的管理,如JDO的pm,那么itemDao.update(this); 是不需要的,也就是说Item是在事务过程中从数据库拿出来的,并 且声明周期不超出当前事务的范围。 3.如果Item是脱离持久层,也就是在Item的生命周期超出了事务的范围,那就要必须显示调用update或attach之类的持久化方法的,这种时候 就应该是按robbin所说的第2种模型来做。 |
胀血模型 基于充血模型的第三个缺点,有同学提出,干脆取消Service层,只剩下domain object和DAO两层,在domain object的domain logic上面封装 事务。 domain object(事务封装,业务逻辑) <---> DAO 似乎ruby on rails就是这种模型,他甚至把domain object和DAO都合并了。 该模型优点: 1、简化了分层 2、也算符合OO 该模型缺点: 1、很多不是domain logic的service逻辑也被强行放入domain object ,引起了domain ojbect模型的不稳定 2、domain object暴露给web层过多的信息,可能引起意想不到的副作用。
个人认为 失血是Hibernate的流行引起的,数据逻辑被分在Dao/imple 层实现 贫血恰恰就是Spring frame的经典MVC,现在在web开发中还是很好的,不够OO?这都不是个事。 充血、胀血没有概念,不过没有看出明显的好处,反而感觉这样做的话,逻辑会很混乱,对于指令编程体系来说,这可不是个好消息。 So,首选还是贫血。至少现在是这么认为的。
DDD 属于充血模型
DDD最大的好处是:接触到需求第一步就是考虑领域模型,而不是将其切割成数据和行为,然后数据用数据库实现,行为使用服务实现,最后造成需求的首肢分离。DDD让你首先考虑的是业务语言,而不是数据。重点不同导致编程世界观不同。
DDD在软件生产流程中定位i如下图,DDD落地实现离不开in-memory缓存、 CQRS、 DCI、 EDA或Event Source几大大相关领域。
四种程序架构
- Clean架构
外圈的层次可以依赖内层,反之不可以,内圈核心的实体代表业务,不可以依赖其所处的技术环境
- DCI架构
DCI (http://www.jdon.com/37976) DCI是数据Data 场景Context 交互Interactions的简称,DCI是一种特别关注行为的模式(可以对应GoF行为模式),而MVC模式是一种结构性模式,MVC模式由于结构化,而可能忽视了行为事件。DCI Architecture是将“是什么”和“做什么”进行分离,然后根据需求在不同场景动态结合,还是桥模式的味道。
- DDD/CQRS 领域驱动设计
CQRS: 命令查询的责任分离Command Query Responsibility Segregation (简称CQRS)模式是一种架构体系模式,能够使改变模型的状态的命令和模型状态的查询实现分离。这属于DDD应用领域的一个模式,主要解决DDD在数据库报表输出上处理方式。
- 六边形架构
允许应用程序都是由用户,程序,自动化测试或批处理脚本驱动的,在事件驱动和数据库环境下被开发和隔离测试。一个事件从外面世界到达一个端口,特定技术的适配器将其转换成可用的程序调用或消息,并将其传递给应用程序。该应用程序是可以无需了解输入设备的性质(调用者是哪个)。当应用程序有结果需要发出时,它会通过一个端口适配器发送它,这个适配器会创建接收技术(人类或自动)所需的相应信号。该应用程序与在它各方面的适配器形成语义良性互动,但是实际上不知道适配器的另一端的谁在处理任务。
心得: 看的头痛!!!