[DDD读书笔记] 构造块①分离领域层

2,436 阅读6分钟

前文回顾

上一篇介绍了该书的第一部分“运用领域模型”,这部分提出领域驱动开发的基本目标,这些目标是后面几部分中所讨论的实践的驱动因素。第一部分还定义了一些术语,并给出了用领域模型来驱动沟通和设计的总体含义。

我们学习了以下几种模式:

  1. 通用语言模式(UBIQUITOUS LANGUAGE)
  2. 模型驱动设计模式(MODEL DRIVEN DESIGN)
  3. 亲身实践的建模人模式(HANDS-ON MODELER)

本篇主要针对第二部分“模型驱动设计的构造块”,将面向对象领域建模中的一些核心的最佳实践提炼为一组基本的构造块。这一部分主要是消除模型与实际运行的软件之间的鸿沟。

本文概要

通过前文,我们知道模型与代码实现应该是紧密相连的,本篇将介绍一组用于构建领域模型的构造块(Building Blocks),使用这些构造块可以帮助我们将模型和程序紧密结合在一起。

模型驱动设计(MODEL DRIVEN DESIGN)导航图 image.png

如何对待领域模型以外的部分

一个软件系统中,用于处理业务逻辑的部分只占整个软件的一小部分,这个部分也就是我们重点关注的领域模型。软件中还有很大一部分是跟领域模型无关的,比如说软件的视觉呈现,网络通信,用户数据持久化,数据格式转换等,这些都是作为软件系统必不可少的,但不包含在领域模型之中。我们应当如何对待领域模型以为的部分呢?作者Eric告诉我们:

如果领域逻辑与程序中的其他关注点混在一起,就不可能实现这种一致性(即领域层的软件和模型概念的一致性)。将领域实现独立出来是领域驱动设计的前提。

早期的面向对象的编码,常常在同一个对象中写入用户界面、数据库访问的代码。而一些业务逻辑则被嵌入到界面组件或者数据库脚本中。查看和分析领域相关的代码非常困难。界面的修改也可能导致业务逻辑的变化。这样做就很难实现具有一致性的模型驱动的对象了。要开发出实现复杂任务的程序,一定要做到关注点分离

领域对象应该将重点放在如何表达领域模型上,而不需要考虑自己的显示和存储问题,也无需管理应用任务等内容。这使得模型的含义足够丰富,结构足够清晰,可以捕捉到基本的业务知识,并有效地使用这些知识。

作者介绍了一种十分常用的分层架构模式(Layered Architecture),他指出大部分软件系统都采用了分层架构,只是采用的具体分层方案有所不同而已。分层的价值在于每一层只关注某一个方面的问题,使程序设计更具有内聚性。分层方案有很多中,而适用与领域驱动设计的分层方案,需要把领域层分离出来,这是实现模型驱动设计(MODEL DRIVEN DESIGN)的关键。作者给出一种分层方案作为参考:

image.png

分层架构模式的基本原则是依赖的单向性,即上层可以依赖下层,而下层不能依赖上层。大家熟知的MVC模式(Modle-View-Controller)就是最早将用户界面层、应用层和领域层分离出来的分层方案。作者Eric举了一个网上银行转账的例子。用户可以选择两个账号,并输入金额执行转账。在应用层开启事务,并调用领域层Account对象的credit和debit方法。技术设施层提供事务管理能力和数据持久化。

image.png

例子中领域模型的交互非常简单易懂。从这个例子可以看出,将领域层分离出来,专注于领域层的设计,可以更好地绘制出表达领域规则的模型。

是否可以不分离领域层

作者介绍了智能用户界面模式(Smart UI),即在用户界面中实现所有逻辑。这听起来像是异端邪说,但有它存在的合理性。作者的原话是:

SMART UI也有其自身的优势,在某些情况下它能发挥最佳的作用。

比如使用Smart UI的开发效率高,对开发人员的技能要求低等等。当然,代码很难重用,不适合开发复杂功能也是这种模式的缺点。如果一个项目只需要提供简单的功能,以数据输入和显示为主,涉及业务规则很少,那么SmartUI不失为一种可行的选项。但是它不能与模型驱动设计兼容,所以在讨论领域模型时,SmartUI经常被作为一种反模式

另外作者Eric还提到了事物脚本模式(Transaction Script),这是Martin Fowler在PoEAA书中首先提出来一种模式。这种模式中,用户界面层被分离出来,但是没有抽象出领域模型。它似乎介于Smart UI和Layered Architecture之间。它适合业务逻辑相对简单的系统,只需要过程式的脚本就能实现。事实上,笔者经历的很多项目都是采用的这种模式。但它显然不支持领域驱动设计。

Layered Architecture并不是唯一适合领域驱动设计的架构,六边形架构(Hexagonal Architecture)和Robert Martin提出的整洁架构(The Clean Architecture)都天然支持领域驱动设计。作者指出:

如果一个架构能够把那些与领域相关的代码隔离出来,得到一个内聚的领域设计,同时又使领域与系统其他部分保持松散耦合,那么这种架构也许可以支持领域驱动设计。

系列文章