领域驱动设计工作坊
上QQ阅读APP看书,第一时间看更新

1.2.4 领域驱动设计和软件复杂度

我们引入DDD的目标是控制软件复杂度。那么,DDD是如何做到这一点的呢?本节将探讨DDD与软件复杂度之间的对应关系。

1.领域驱动设计和规模

我们先来看一个示例。图1-33展示了一张UML中的用例图,其中涉及工单系统中的一个常见用例。

图1-33 工单系统常见用例

针对图1-33,我们可以采用DDD中的设计方法进行建模和拆分,从而得出一组子域,如图1-34所示。

图1-34 工单系统子域

我们可以将图1-34中的每个子域映射为限界上下文,并梳理限界上下文之间的关联关系,如图1-35所示。

图片1

图1-35 工单系统中限界上下文的交互过程

在图1-35中,U代表上游,D代表下游。位于下游的Ticket上下文会分别调用位于上游的其他3个限界上下文。通过这种方式,我们对系统进行了合理的拆分,从而降低了因规模导致的软件复杂度。这也是DDD中应对这一软件复杂度问题的基本手段。

2.领域驱动设计和结构

在DDD中,为了应对由于结构导致的软件复杂度,通常会引入一组架构模式。图1-36展示的就是最基础的DDD分层架构模式。

可以看到,这里将系统分为用户接口层、应用层、领域层及基础设施层4个层次,并梳理了各个层次之间的调用关系。这是一种常见的DDD架构模式,但并不是DDD中唯一可以采用的架构模式,我们也可以采用图1-37所示的六边形架构来对系统结构进行合理组织。

图1-36 DDD分层架构模式

图1-37 DDD六边形架构模式

在DDD中,常见的架构模式还包括五层分层架构、整洁架构等。关于分层架构、六边形架构及其他DDD架构模式的讨论,请参考第11章。需要牢记的是,无论采用何种架构模式,目的都是降低由于结构不合理而导致的软件复杂度。

3.领域驱动设计和变化

应对变化所引起的软件复杂度的基本思路是抽象,那么DDD是如何实现抽象过程的呢?本质上是依靠它的领域对象。我们在1.2节讨论DDD战术设计维度时已经知道DDD领域对象包括聚合、实体和值对象3种类型,它们之间存在图1-38所示的包含关系。

图1-38 3种领域模型对象的结构包含关系

可以看到,聚合内部包含实体和值对象,而实体和值对象既可以单独存在,也可以在实体中嵌入值对象。实体具有操作行为和状态可变性,而值对象则只关注数据属性。这两种领域对象很好地封装了业务本身的属性和状态。另外,聚合的作用在于管理领域对象之间的交互过程,一个聚合内部的所有对象只能通过聚合根进行访问,从而有效降低了对象之间的交互复杂度,如图1-39所示。

图1-39 通过聚合根降低对象交互复杂度

本质上,聚合、实体和值对象体现的是一种抽象机制,抽象的切入点包含数据属性、操作行为、可变状态及交互方式。通过前面内容的分析,我们可以基于DDD来应对系统中的各种变化,并通过抽象手段降低软件复杂度。