乐者为王

Do one thing, and do it well.

贫血领域模型

英文原文:https://martinfowler.com/bliki/AnemicDomainModel.html

贫血领域模型是那些已近存在了相当长时间的反模式中的一份子,然而目前似乎有一个特定的高潮。我和Eric Evans聊过这个,并且我们都注意到它们似乎越来越流行。作为真正的领域模型支持者,这不是一件好事。

贫血领域模型的基本症状是乍一看它就像真的领域模型一样。这些对象大多以领域空间中的名词命名,并且它们被真正的领域模型拥有的丰富的关系和结构连接。当你观察行为时问题来了,你意识到这些对象几乎没有任何行为,仅仅只是封装了getter和setter方法。这些模型的设计规则往往说不要把任何领域逻辑放到领域对象里。取而代之的是一组服务对象捕获了所有的领域逻辑。这些在领域对象上层的服务把领域对象当数据使用。

这种反模式最根本的恐怖在于它和面向对象设计的基本理念完全相反,它只是把数据和处理结合在一起。贫血领域模型其实只是一种过程式风格的设计,正是那种像我(和Eric)自Smalltalk早期以来一直在与之作斗争的顽固者。更糟糕的是,许多人认为贫血对象是真正的对象,因此完全没有抓住面向对象设计是怎么回事的要领。

现在面向对象的纯粹主义当然很好,但我意识到我需要更多的基本论据来反对这种贫血症。本质上贫血领域模型的问题是它们承担了领域模型所有的成本,没有产生任何的好处。主要成本是映射到数据库的笨拙,它通常会导致一整层的O/R映射。在而且只有在你使用强大的面向对象技术去组织复杂的逻辑时这才值得。通过把所有的行为拉取到服务中,不管用什么方法,基本上你最后得到的都是事务脚本,从而失去领域模型能带来的优势。正如我在《企业应用架构模式》中讨论过的,领域模型并不总是最好的工具。

值得强调的是,把行为放进领域对象不应违背利用分层将领域逻辑从诸如持久和表现责任中分离的坚实方法。在领域对象中的逻辑应该是领域逻辑——验证、计算、业务规则——无论你喜欢叫它什么。(某些情况下,你会产生把数据源和表现逻辑放到领域对象里的争论,但它和我对贫血症的看法无关。)

这一切混乱的来源是许多OO专家强烈推荐在领域模型顶部放一层过程式服务,来形成一个服务层。但这不是让领域模型完全没有行为的一个论据,其实服务层主张服务层要和行为丰富的领域模型一起使用。

Eric Evans的精彩书籍《领域驱动设计》有如下的文字谈及这些层:

应用层【他对服务层的命名】:定义软件可以完成的工作,并且指挥具有丰富含义的领域对象来解决问题。这个层所负责的任务对业务影响深远,对跟其它系统的应用层进行交互非常必要。这个层要保持简练。它不包括处理业务规则或知识,只是给下一层中相互协作的领域对象协调任务、委托工作。在这个层次中不反映业务情况的状态,但反映用户或程序的任务进度的状态。

领域层(或者模型层):负责表示业务概念、业务状况的信息以及业务规则。并且保持这些内容的技术细节由基础结构层来完成,反映业务状况的状态在该层中被控制和使用。这一层是业务软件的核心。

这里的关键点是服务层是瘦的——所有的关键逻辑存在于领域层。他在服务模式中重申了这个观点:

现在,最常犯的错误就是太轻易地放弃把这种行为配置到合适的对象上,逐渐地滑向过程式编程。

我不知道为什么这个反模式如此常见。我猜想它是因为大多数人还没有真正地和正确的领域模型工作过,特别是如果他们有数据背景。有些技术鼓励正确的领域模型,例如J2EE的实体Bean,它是我偏爱POJO领域模型的理由之一。

总之,你在服务中发现越多的行为,你就越难体会到领域模型的好处。如果你所有的逻辑都在服务中,那你将得不到任何好处。

Comments