这是已经存在了很长一段时间的反模式之一,但目前似乎正在发生特别的迸发。我们都注意到他们似乎越来越受欢迎。作为一个合适的领域模型的推动者,这不是一件好事。
一个贫血的领域模型的基本症状是,乍一看它看起来像真实的东西。有一些对象,许多以域空间中的名词命名,并且这些对象与真实域模型具有的丰富关系和结构相关联。当你观察这些行为的时候,你会发现这些东西几乎没有任何行为,它们只是一堆的getter和setter。事实上,这些模型经常带有设计规则,表明您不应该将域逻辑放入域对象中。取而代之的是一组服务对象,它们捕获所有的域逻辑,执行所有的计算,并使用结果更新模型对象。这些服务位于领域模型的顶部,并使用域模型作为数据。
这种反模式的根本恐怖之处在于它与面向对象设计的基本思想相悖;也就是将数据和过程结合在一起。贫血的领域模型实际上只是一个过程式的设计,就像我(和Eric)一样,自我们在Smalltalk的早期就一直在斗争的东西。更糟糕的是,许多人认为贫血的对象是真正的对象,因此完全忽略了面向对象设计的要点。
现在,面向对象的语言是很好的,但是我意识到我需要更多的基本论点来反对这种贫血。实质上,贫血领域模型的问题在于它们承担了领域模型的所有成本,而没有产生任何好处。主要成本是对数据库的映射的笨拙,通常会导致整个O/R映射。如果您使用强大的面向对象技术来组织复杂的逻辑,这是值得的。然而,通过将所有行为都导出到服务中,基本上会以事务脚本结束,从而失去域模型带来的好处。
同样值得强调的是,将行为放到域对象中不应该与使用分层来将域逻辑与持久化和表示职责分开的可靠方法相矛盾。应该在域对象中的逻辑是域逻辑 - 验证,计算,业务规则 - 无论你喜欢怎么称呼它。(有些情况下,当您在域对象中放置数据源或表示逻辑时发生争论,但这与我对贫血症的观点正交。)
所有这一切的混乱之处在于,许多面向对象的专家建议在域模型之上建立一层程序服务,以形成服务层。但这并不是一个使域模型无效的参数,实际上服务层主张使用一个服务层与一个行为丰富的域模型相结合。
Eric Evans的优秀的书籍领域驱动设计有以下几层。
应用层[服务层名称]:定义软件应该做的工作,并指导表达域对象解决问题。该层负责的任务对业务有意义或者与其他系统的应用层进行> 交互所必需的。这层保持薄。它不包含业务规则或知识,但只负责协调任务,并将任务委托给下一层的域对象的协作。它没有反映业务情> 况的状态,但它可以具有反映用户或程序的任务进度的状态。
域层(或模型层):负责代表业务的概念、业务情况的信息和业务规则。反映业务情况的状态在这里被控制和使用,即使存储它的技术细节被委托给基础设施。这一层是商业软件的核心。这里的关键点是服务层很薄——所有的关键逻辑都在域层中。他在他的服务模式中重申了这一点:
现在,更常见的错误是过于轻易地将行为融入适当的对象,逐渐滑向过程式编程。
我不知道为什么这种反模式如此普遍。我怀疑这是由于许多人没有真正使用合适的领域模型,特别是如果他们来自数据背景。一些技术鼓励它;比如J2EE的Entity Beans,这是我更喜欢POJO领域模型的原因之一。一般来说,您在服务中发现的行为越多,就越有可能抢夺领域模型的好处。如果你所有的逻辑都在服务中,那么你已经失明了。
POJO
首字母缩略词: 普通旧式Java对象(Plain Old Java Object)。
在谈话中,我们指出了将业务逻辑编码为普通Java对象而不是使用Entity Beans的许多益处。我们想知道为什么人们反对在他们的系统中使用常规对象,并得出结论,这是因为简单的对象缺乏一个奇特的名字。所以我们给了他们一个,并且它很好地被抓住了。