Skip to the content.

贫血领域模型

这是一个用了很长一段时间的反模式了,它似乎还会存在与一段时期。我和 Eric Evans 一起讨论过这些,我们都注意到它越来越受欢迎了。作为一个领域模型的强有力的支持者来说,这不是不好的。

贫血领域模型基本症状就是刚开始看起来是像真的。有一些对象很多都是以域空间的名词命名的,并且那些对象和具有丰富的关系和结构的领域模型关联起来。当你观察它们行为的时候就会发现问题,你就认识到这些对象实体机会没有任何行为,只是使他们充斥越来越多的 getter 和 setter。的确在这些模型被设计之初,在领域模型上你经常是不知道任何领域逻辑的。取而代之的是一系列的服务对象,他们都含有所有的领域逻辑,关注所有的计算和模型更新的结果。这些服务存在于领域模型之上并用于领域模型数据。

这个反模式基本上令人恐惧的是他是与面向对象设计的思想是相反的;它把数据和处理整合到了一起。贫血领域模型是过程式的设计风格,这正是像我和 Eric 这样的对象偏执狂从一开始就从 Smalltalk 里就开始斗争。这有什么问题,很多人认为贫血对象是真正的对象,因此完全忽略了面向对象设计的意义。

现在纯粹的面向对象就很多,但是我意识到我需要更基本的论据来反对这种贫血模型。贫血另有模型本质问题是它们要承受领域模型的所有的代价,没有任何好处。主要的成本就是以笨拙的方式映射到数据库,在整个 O/R 映射层指定结果。通过获取所有的行为到服务中去,然而你最终得到还是事务脚本,因此丢失了领域模型能带来的优势。就像我之前讨论的 P of EAA 一样,领域模型并不总是最佳工具。

值得强调的是将行为放入领域对象,不应该使用分层来分离领域逻辑如持久化层和显示层的方法相冲突。领域逻辑应该在领域对象里面 — 验证,计算,业务规则 — 一切你要调用的。(在某些情况下,你需要将数据源或表示逻辑放入领域对象中,但是这与我关于贫血模型的观点相交。)

在很多面向对象专家里所有结论中,其中之一就是建议要将过程服务放置到领域模型智商,为了行为一个服务层。但这不是使领域模型的行为无效的一个论据,实际上服务层倡导者拥护使用服务层来组合行为到丰富的领域明显中去。

Eric Evans 的杰出数据驱动领域设计就关于这些层说了如下观点。

应用层[也就是服务层]:定义软件支持去做的任务以及直接表示领域对象去处理问题。这层的任务就是响应业务的意思或者是其他系统应用层必要的交互。这层要很薄。它不应该包含业务规则或知识,只协调任务和将工作委托给下一层的领域对象的协作。它不能有反应出业务情景的状态,但是能有反应出用户或程序的任务的进度状态。

领域层(或模型层):负责表示关于业务情景的概念,信息,以及业务规则。反映业务情景的状态要在这里控制和使用,甚至是存储的技术细节被委托到基础设施。这层是业务软件的核心。

关键就是服务层要薄 —— 所有的关键逻辑要存在与领域层。他在他的服务模式中重申了这点:

现在,更多共同的错误就是太容易放弃,在填充行为到合适的对象,逐渐转向到了过程式编程。

我不知道为什么这个反模式如此常见。我怀疑是由于很多人他们都没有真正用合适的领域对象工作过,特别是如果他们来及数据后台。一些技术都会遇见它;比如 J2EE 的实体 Beans,它就是我倾向与 POJO 领域对象的其中一个理由。

通常,你会发现在服务中有越来越多的行为,它更有可能让你在领域模型中获益。如果你所有的逻辑都在服务里,那么你得担心自己的眼睛了。

https://martinfowler.com/bliki/AnemicDomainModel.html