全书共分为3个部分
第一部分 基础
讲构成DDD的基础概念元素,以及如何在建模过程中使用这些概念.
业务模型由对象和对象关系构成了一张复杂的对象图,称之为业务模型.主要讲了如何处理对象关系;对象包含哪些类型(实体,值对象,服务,工厂,仓库);对象图如何划分(聚合,模块).
- 关联
对象之间的关联,在对象图中用线表示,代表某种业务关系,如:属于,拥有,包含等等.
访问对象可以有两种方式,一种是利用对象之间的关联关系,进行遍历访问,另一种则是通过Repository
进行全局访问.
为了简化对象图中的复杂关联关系,通常进行以下操作:
(1)规定一个遍历方向,使无向边变为有向边
(2)添加一个限定符,以便减少多重关联.
举例:
一个国家可以有多位总统,表示为: 国家 --> List<总统>
但是如果考虑一段时间内一个国家只有一位总统,那么以时间段作为限定符,可以将一对多关系简化为约束的一对一关系,表示为: 国家 --> Map<时间段,总统>
(3)消除不必要的关联,删除掉对解决业务问题无关的边. - 实体
实体具有唯一标识,随着时间推移,其生命周期内状态(或叫属性)会连续变化,我们需要根据标识,来跟踪对象状态的变化,这种对象叫做实体.
在实体设计时,定义标识是关键步骤.
在建模时通常定义一个通用接口Entity
,让实体类显示实现接口,便于对象分类. - 值对象
值对象没有概念上的唯一标识,它们用于描述某种特征.如:Color
类用于描述颜色.
值对象可以引用实体,实体也可以引用值对象.
值对象一般是不可变的,这里的不可变指的是值对象内部的引用关系不可变.
如:一个值对象引用一个实体,这种引用关系不可变,但实体内部状态可以改变.
值对象不可变的特性,可以方便其被其他对象共享,并确保引用传递的安全性.
值对象内部属性变更,通常通过原型模式创建新对象来完成. - 服务
业务领域中有一些操作,不适合归属于任何对象,因此单独归属为Service
.
它们往往以活动命名,是动词而不是名词,并带有Manager后缀.
服务对象无状态. - 工厂
如果对象创建也是一个复杂的过程,应该让Factory
承担这个复杂的装配过程. - 仓库
就是解决从存储介质中重建对象的,为业务提供实体全局访问的能力.
与工厂的区别是,工厂解决的是新建的问题,仓库解决的是存储,检索和重建的问题. - 聚合
前文提到对象图是一张巨大且复杂的网络图,这其中某些对象之间需要满足一些固定的业务规则限制,如:退款交易总金额不能超过原支付金额;货物总重不能超过运输船容量;等等.聚合就是用来识别和划定一致性范围的.
聚合指的是具有一致性规则约束的一组对象的集合,它本质上是一致性规则约束的范围边界.
每个聚合都有一个实体作为根对象,外部只能通过聚合根访问或操作聚合边界内部的对象,而无法直接访问.
聚合内对象也可以关联其他聚合的根对象.
聚合内部的一致性约束和聚合间的关联,最终映射到事务上,表现为事务的嵌套.
聚合如果想要通过编码体现的话,通常是通过分包的方式,把聚合内对象分到一个包中.
- 模块(domain与其他层的划分,domain内部划分)
模块也是对象图的划分方式,核心解决的是认知超载的问题,使我们可以对业务问题进行聚焦.
上文提到,聚合可以通过模块划分的方式,在代码中具体体现.
当然,多个内聚的聚合也可以整合为更大的父模块.
再进一步,所有领域对象再整合为更大的父父模块domain,与application,infrastructure并列构成整个应用,形成了分层架构.
总体如下:
application
domain
|-- aggregate
|-- entity
|-- value object
infrastructure
第二部分 保持重构
这部分核心传递了一个思想,就是要敢于重构,根据自己对业务不断的认知迭代,去精化业务模型.还讲述了如何通过柔性设计来让模型易于被修改.
这里面强调的是模型的表达,和对象的设计两个方面.
模型表达,让后人易于理解,敢于修改.
对象设计,让修改变的容易,且对现状的冲击小.
第三部分 战略设计(限界上下文,精炼,大型结构)
这部分更多解决的是企业级业务模型面临的问题.
所谓企业级,特点是业务概念多而复杂,组织架构划分也可能导致不同团队业务模型不统一,对系统集成和业务认知都存在阻碍作用.
通过定义限界上下文,把企业级业务模型问题转化为限界上下文之间的集成问题.
分别介绍了共享内核,客户/供应商模式,追随者模式,防腐层模式,各行其道模式等几种不同的集成方式.
还介绍了如何通过精炼,产生企业级模型的高度概览视角.
最后,是如何组织大型结构,以及如何表达大型结构.