来源:juejin.cn/post/6917125801460629518前言要想深入把握和理解DDD领域驱动设计的核心,无论如何都绕不开两个相对抽象的概念。——“贫血模型”、“拥塞模型”:贫血模型即事务脚本模式。拥塞模型是领域模型模式。贫血模型贫血模型最先广泛应用在EJB2中,是Spring最繁荣时期创造的。它将:“行为”(逻辑、过程);分离成不同的对象:只有状态的对象是所谓的“贫血对象”(通常称为VO-值对象);只有行为的对象就是我们常见的N层结构中的Logic/Service/Manager层(对应EJB2中的StatelessSessionBean)。——Spring的作者RodJohnson也承认,Spring只是在沿袭EJB2时代的“事务脚本”,即面向过程的编程。贫血领域模型是一种存在已久的反模式,至今仍有许多拥护者。当MartinFowler和EricEvans聊起这件事时,这个模型似乎越来越受欢迎。作为领域模型的推动者,他们觉得这不是什么好事。贫血领域模型的基本特征是乍一看与它完全一样。项目中有很多对象,都是按照域来命名的。对象之间存在丰富的联系,与真实的领域模型非常相似。但是当你检查这些对象的行为时,它们基本上没有任何行为,只是一堆getters/setters。实际上,这些对象在设计之初就被定义为只包含数据,不能添加到领域逻辑中;逻辑必须写入一组称为服务的对象;而Service建立在领域模型之上,需要使用这些模型来传递数据。这种反模式的可怕之处在于它完全反对面向对象的设计。面向对象设计提倡将数据和行为绑定在一起,而贫血领域模型更像是一种面向过程的设计。MartinFowler和Eric在他们还是Smalltalk的时候就强烈反对这种做法。更糟糕的是,很多人认为这些贫血的领域对象是真实的对象,完全误解了面向对象设计的意义。既然面向对象的概念很普遍,就需要更多的论据来反对这种贫血的领域模型方法。贫血领域模型的根本问题是它引入了领域模型设计的所有成本,却没有任何好处。最重要的成本是将对象映射到数据库,从而产生O/R(对象关系)映射层。只有充分利用面向对象的设计来组织复杂的业务逻辑,才能抵消这种成本。如果您将所有行为写入服务对象,您最终会得到一组事务脚本,并且会错过域模型的好处。正如Martin在《EnterpriseApplicationArchitecturePatterns》一书中所说,领域模型不一定是最好的工具。将行为放入领域模型与分层设计(领域层、持久层、表现层等)并不冲突。因为领域模型将领域相关的逻辑——验证、计算、业务规则等放入其中。如果要讨论数据源或表示逻辑是否可以放入领域模型,这超出了本文的范围。一些面向对象的专家有时会混淆观点,他们认为确实应该有一个面向过程的服务层。然而,这并不意味着领域模型不应该包含行为。事实上,服务层需要与一组行为丰富的领域模型结合使用。EricEvans的DomainDrivenDesign书中提到:应用层(即Service层)描述了应用程序要完成的工作,并派发丰富的领域模型来完成。这一层的任务是描述业务逻辑,或者与其他项目的应用层进行交互。这一层很薄,不包含任何业务规则或知识,仅用于对下一层的领域模型进行任务调度和分派。该层没有业务状态,但可以为用户或程序提供任务状态。领域层(或模型层)代表业务逻辑、业务场景和规则。这一层会控制和使用业务状态,即使状态最终会交给持久层存储。总之,这一层是软件的核心。服务层很薄——所有重要的业务逻辑都写在领域层。他在服务模式中重申了这一点:今天人们常犯的一个错误是没有花时间将业务逻辑放入适当的域模型中,从而导致面向过程的编程。我不清楚为什么这种反模式如此普遍。我怀疑这是因为大多数人没有使用过设计良好的领域模型,尤其是以数据为中心的开发人员。此外,还有一些技术也推动了这种反模式,比如J2EE的EntityBeans,这会让我更倾向于使用POJO域模型。总之,如果您将大部分行为放在服务层中,那么您将失去领域模型的好处。如果您将所有行为都放在服务层中,那么您将无可救药。优点很简单:对于只有少量业务逻辑的应用,用起来很自然;开发快速且易于理解;注意:不能完全排除这种方法。缺点不能很好地处理复杂的逻辑:比如收入确认规则的变化,比如4月1日前签订的合同必须使用某条规则...与欧洲签订的合同使用另一种规则...充血模型对象的本质面向设计是:“一个对象有状态和行为”。比如一个人:眼睛鼻子长什么样子就是状态;一个人会玩游戏,会写程序,这就是行为。为什么要有“人事经理”这种东西来帮助人“玩游戏”呢?举一个简单的J2EE案例,设计一个与用户(User)相关的功能。传统的设计一般是:类:User+UserManager;保存用户调用:userManager.save(Useruser)。血腥的设计可能是:class:User;保存用户调用:user.save();用户有一个行为:保存自己。事实上,它们并没有任何特定的适用方向。我个人更喜欢一直使用拥塞模型,因为OOP总是比面向过程的编程语义更丰富,组织更合理,可维护性更强——当然,也更难。掌握。所以,在实际的工程场景中,要不要用,怎么用,还取决于设计者和团队对充血模型设计的理解和把握,因为现在大部分J2EE开发者都深受贫血模型的影响。另外,在实际工程场景中使用充血模型的时候,会遇到很多很多的细节问题。最大的难点是“如何设计充血模型”或者“如何将恰到好处且包含语义的逻辑从复杂的业务中分离出来,放到VO行为中”。如果一个对象中包含了其他对象,职责会继续被委托,业务逻辑会由具体的POJO来执行,使得策略模式更加细粒度,而不是写ifelse。近期热点文章推荐:1.1,000+Java面试题及答案(2021最新版)2.别在满屏的if/else中,试试策略模式,真的很好吃!!3.操!Java中xx≠null的新语法是什么?4、SpringBoot2.5发布,深色模式太炸了!5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!
