作者:Martin Fowler 译者:刘晓日

贫血模型作为众多反模式中的一份子,已经有悠久的历史了,而且现在势头正旺。在我与Eric Evans的交谈中得知,我们都注意到贫血模型开始越来越流行了。这对于纯粹领域模型的忠实粉丝或许不是一件好事儿。

贫血模型一个明显的特征是它仅仅是看上去和领域模型一样,都拥有对象、属性、对象间通过关系关联。但是当你观察模型所持有的业务逻辑时,你会发现,贫血模型中除了一些getter和setter方法,几乎没有其他业务逻辑。这种情况事实上是由一些设计规则中(design rules)规定不要把业务逻辑放到“领域模型”中造成的,取而代之的是把所有的业务逻辑都封装到众多service中。这些service对象在“领域对象”(领域层)之上形成一个service层,而把“领域对象”当做数据使用。

贫血模型从根本上就违背了面向对象设计将属性与操作融合的思想。贫血模型就是我们纯粹的面向对象忠实者(比如我和Eric)从Smalltalk早期就极力反对的面向过程化设计的风格。更糟糕的是,很多人认为贫血模型就是真正的面向对象,进而也就完全领悟不到面向对象设计的真谛。

纯粹的面向对象已经很好了,但是,我知道我需要列出更多的论点去反驳贫血模型。贫血模型一个致命的缺陷就是与领域模型所消耗同样多的资源,却没有得到任何领域模型所具有的优点。这种消耗主要在建立与数据库的映射上,这样就单独划分出一层专注于O/R映射。当你使用功能强大的面向对象技术时,这样做是值得的。而这种将业务逻辑统统放到service中是赤裸裸的面向事务编程的方式,这样领域模型所能带来的优势消失殆尽。然而就像我在“P of EAA”中所说的那样,领域模型并不总是“银弹”。

这里值得强调一下,将业务行为放到领域模型同使用分层技巧将领域逻辑、持久层和展现层分离是不冲突的。不管你喜欢叫它什么,领域模型所持有的逻辑(比如验证、计算、业务规则等)就叫领域逻辑。(有时候你可能会力主在领域对象里加入数据源或表示逻辑,但这和我说的贫血无关)(注:此句来自豆他爹。超级感谢豆他爹的翻译,太犀利了,看完我就觉得就是这样啊,醍醐灌顶的感觉。)

造成面向对象现状混乱的一个主要因素是许多面向对象专家就建议在领域模型之上增加一个service层。但是这不能作为不把领域逻辑放到领域模型中的依据,事实上service层应该结合领域模型中持有的领域逻辑方法一起使用。

在享誉全球Eric Evans大师的《领域驱动设计》一书中,这样描述这些层的职责(应用层、领域层翻译引自《领域驱动设计-软件核心复杂性应对之道》一书44页):

应用层(service层):定义软件要完成的任务,并且只会表达领域概念的对象来解决问题。这一层所负责的工作对业务来说意义重大,也是与其他系统的应用层进行交互的必要渠道。 应用层赢尽量简单,不包括业务规则或者知识,而只为下一层中的领域对象协调任务,分配工作,使他们互相协作。它没有反应业务情况的状态,但是却可以具有另外一种状态,为用户或程序显示某个任务的进度。

领域层(或模型层):负责表达业务概念,业务状态信息以及业务规则。尽管保存业务状态的技术细节是有基础设施层实现的,但是反应业务情况的状态是有本层控制并且使用的。领域层是业务软件的核心。

这里所说的关键点是service层很薄(所有业务逻辑都在领域层)。Eric Evans在service层中反复强调这个观点:

如今,在实践DDD过程中最常见的错误是,过早的放弃将领域逻辑放到一个合适的领域模型中,从而滑向了过程化编程的“深渊”。

如今,不知道为什么这种反模式可以当道,据我揣测,可能是众多的开发人员,尤其是有从事数据相关背景的开发人员,根本就没有使用过纯粹的领域模型。有些技术鼓励使用领域模型,比如J2EE中的实体Bean。这也是我喜欢POJO领域模型的原因。

总之,将越多的领域逻辑放到service中,你就越难体会到领域模型带来的好处。如果你所有的领域逻辑都在service中,那你得不到任何领域模型带来的好处。

原文地址:http://martinfowler.com/bliki/AnemicDomainModel.html

声明,本文为原创翻译,由于小人才疏学浅,加之第一次翻译e文,如有不合适的地方,烦请各位指正。

其中有些地方加入自己的理解,如理解错误,望见谅。