[DDD读书笔记] 构造块③模块

698 阅读7分钟

前文回顾

上一篇介绍了该书的第二部分“模型驱动设计的构造块”,将面向对象领域建模中的一些核心的最佳实践提炼为一组基本的构造块。我们了解了建模所需的重要元素:实体(ENTITY)、值对象(VALUE OBJECT)和服务(SERVICE)。

这一篇我们继续学习该书的第二部分。

模型元素如何分组

模块(MODULE) 是我们熟知的一种传统的软件设计方法。模块的设计要求遵循高内聚、低耦合的原则。虽然在设计其他的对象时,也会要求做到高内聚、低耦合,但是模块作为一种更粗粒度的设计元素,遵循这一原则更为重要。

模块之间低耦合和模块内部高内聚的设计原则,使得MODULE听上去像是一种技术指标,仿佛是根据关联和交互的分布情况来机械地判断它们。

然而,MODULE并不仅仅是代码的划分,而且也是概念的划分

在划分模块时,选择能够描述系统的MODULE,并使之包含一个内聚的概念集合。基于这个概念组织的MODULE可以用一种有意义的方式将模型元素集中到一起。这就是领域模型中MODULE的使用方式,如果说模型讲述了一个故事,那么MODULE就是这个故事的各个章节。

MODULE为人们提供了两种观察模型的方式,一是可以在MODULE中查看细节,而不会被整个模型淹没,二是观察MODULE之间的关系,而不考虑其内部细节。

前文我们介绍过分层架构(LAYERED ARCHITECTURE),这种框架设计是在尝试解决两个合理的问题。

一个问题是关注点的逻辑划分:一个对象负责数据库访问,另外一个对象负责处理业务逻辑,等等。这种划分方法使人们更容易(在技术层面上)理解每个层的功能,而且更容易切换各个层。

另一个动机是层的分布。如果不同层的代码实际上被部署到不同的服务器上,那么这会成为这种分层的有力论据。

那么这种做法有什么问题吗?有的,作者Eric指出这种设计的问题之一在于没有顾及应用程序的开发成本。如果在MODULE设计中也采用分层架构,那么开发工作量将成倍增加。另一个问题在于,实际上通常的项目并不需要将各个层分布到不同的服务器上。对领域建模来说,分层架构可能导致模型对象实现的分裂,也就是一个领域对象的实现分布在不同的层中。我们需要注意:

除非真正有必要将代码分布到不同的服务器上,否则就把实现单一概念对象的所有代码放在同一个模块中(如果不能放在同一个对象中的话)。

模型元素之间有什么关系

在创建领域模型的时候,除了画出这些元素,还需要画出元素之间的关联关系。为了使模型和实现不至于变得太复杂,尽可能地对关联关系进行约束是非常重要的。有3种方法可以使得关联更易于控制:

(1)规定一个遍历方向。

(2)添加一个限定符,以便有效地减少多重关联。

(3)消除不必要的关联。

作者举了一个总统的例子用来说明遍历方向的优化。说有两个对象国家(Country)和个人(Person),个人可以成为国家的总统(President),这是一种关联关系,而且是一对多的双向关联。我们会经常从一个国家联想到它的总统,而当提到“乔治·华盛顿”这个名字时,我们很少会问他是哪个国家的总统。所以从实用的角度讲,我们可以将这种关系简化为从国家到总统的单向关联。

image.png

一般的,一个国家在一个时间段里只会有一个总统。那么我们就可以添加一个限定,将一对多的关联简化为一对一的关联。而且,这种被约束的关联可以传递更多的信息。

image.png

对于VALUE OBJECT关联,作者Eric特别指出:

如果说ENTITY之间的双向关联很难维护,那么两个VALUE OBJECT之间的双向关联则完全没有意义

有哪些建模范式

作者Eric所指的建模范式指的是建模方法论,比如说面相对象建模,关系数据库建模等等。

MODEL DRIVEN DESIGN要求使用一种与建模范式协调的实现技术。人们曾经尝试了大量的建模范式,但在实践中只有少数几种得到了广泛应用。目前,主流的范式是面向对象设计。

但是MODEL DRIVEN DESIGN并不是说必须将每个元素都设计为对象。一些工具还支持其他的模型范式,如业务规则引擎(BUSINESS RULE ENGINE)。项目需要在它们之间做出契合实际的折中选择。这些其他的工具和技术是MODEL DRIVEN DESIGN的补充,而不是要取而代之。

当领域的主要部分明显属于不同的范式时,明智的做法是用适合各个部分的范式对其建模,并使用混合工具集来进行实现。混合使用不同的范式使得开发人员能够用最适当的风格对特殊概念进行建模。

这也就是将业务规则引擎或工作流引擎这样的非对象组件集成到对象系统中的动机。此外,大部分系统都必须使用一些非对象的技术基础设施,最常见的就是关系数据库。作者提醒我们,在使用不同的范式后,要想得到一个内聚的模型就比较困难了。

如果项目中采用了业务规则引擎,那么团队必须找到一种同时适用于两种范式的单一模型。与领域模型中的概念规则相比,引擎中的规则更像是一些较小的程序。只有保持规则与对象之间紧密、清晰的关系,才能确保显示出这二者所表达的含义。

将各个部分紧密结合在一起的最有效工具就是健壮的UBIQUITOUS LANGUAGE,它是构成整个异构模型的基础。

作者根据自身的经验告诉我们,在决定使用混合范式之前,一定要确信主要范式中的各种可能性都已经尝试过了。如果一定要将非对象元素混合到以面向对象为主的系统中时,需要遵循以下4条规则:

不要和实现范式对抗。用别的方式来考虑领域。找到适合于范式的模型概念。

把通用语言(UBIQUITOUS LANGUAGE)作为依靠的基础。

不要一味依赖UML。

保持怀疑态度。是否真的有必要?不能因为存在一些规则,就必须使用规则引擎。

关系范式是范式混合的一个特例。作为一种最常用的非对象技术,关系数据库与对象模型的关系比其他技术与对象模型的关系更紧密,因为它作为一种数据持久存储机制,存储的就是对象。

系列文章