领域驱动设计入门流程
主要是从围绕组织的业务模型定位到编码域模型的过程。
基础流程
- 对齐:业务模型对齐需求
- 发现:对领域实现可视化和协作
- 解耦:将领域分为子域
- 连接:将子域形成为一种松耦合架构
- 战略:专攻业务差异化的核心子域
- 组织:按照有界上下文组织团队
- 定义:定义每个有界上下文的角色和职责
- 编码:使用战术模式实现有界上下文
基础划分
领域驱动设计将软件系统的设计分为两个部分:战略设计和战术设计。在战略设计层面提出域、子域、限界上下文等概念;在战术设计层
面提出了实体、值对象、领域服务、领域事件、聚合、工厂、资源等重要概念
战略设计部分指导我们如何按照领域驱动的模型将一个复杂系统进行拆分;战术设计部分指导我们将拆分出来的模块落地以及落地过程
中应遵循的原则。
领域驱动设计在微服务时代大行其道的主要原因是因为领域设计的战略部分将将系统划分为不同的’域’,这与微服务架构体系中将一个
单体应用拆分为不同的微服务解决的是同一个问题。
'域’解决的是空间问题;限定上下文解决的是解决空间方案(ps:可以将域理解成为一个具体的车间,限定上下文可以理解为车间中进行某
一步生产活动的生产资料)
传统的分层架构
| 终端显示层 | 开放接口 |
web层 |
---|
service |
| manager层
DAO层 |
---|
DB |
在传统分层架构中
-
service层
业务逻辑服务层:承担的是具体的业务逻辑服务 -
manager层
通用业务处理层,承担的是 -
对第三方接口进行封装,预处理返回结果及转换异常信息
-
对service层中的通用能力的下沉(ps:也就是说将通用的service中的能力下沉到manager层)
-
与DAO层的封装,对DAO层的组合复用(ps:可以将事务放到manager层来控制)
缺陷或不足:
- service层和manager层在实际开发中没有明显的特征,容易将manager层演化成为一个特殊的业务属性淡化的service层
根据六边形架构的指导思想,将一个实际的应用划分为四层:
1.用户接口层:负责用户展现相关的逻辑
2.应用层:将一个用例进行流程编排(将接口用例分成若干步骤,但是不负责每步的具体实施)(ps:定义流程接口)
3.领域层:负责实现核心的领域逻辑(业务逻辑)
4.基础设施层:所以依赖的具体实现
倒置的分层架构
领域模型的特定
- 对业务领域进行建模
- 细粒度的类,易于扩展和复用
- 可应对复杂的业务逻辑
- 需要经验才能掌握
- 简单领域模型
- 几乎和数据库实体一一对应
- 复杂领域模型
- 使用继承、组合、设计模式各种手段
在整个软件开发的周期中尽量使用领域名称来进行沟通、在代码中尽量让命名贴近于领域对象。
DDD分层架构
名称 | 作用 |
---|---|
用户界面/展示层 | 负责向用户展现信息以及解释用户命令 |
应用层 | 很薄的一层,用来协调应用的活动。不包含业务代码逻辑,不保留业务对象状态,但应保留应用任务进度状态 |
领域层 | 本层包含关于领域的所有信息,是业务软件的核心所在,在这里保留业务对象的状态和行为。 |
基础设施层 | 作为底层基础层,提供其他层的基础功能,例如持久化、通用功能等 |
领域层
-
实体
- 对象不是由属性定义的,而值标识定义的
- 对象内容的变化不会影响标志符(ps:可以理解为对象内容的变化本身就是对象的一种合理行为)
- 持久化不会影响标志
- 实体属性的选择
实体对象属性应是标识、查找、匹配对象的最基本特征;只添加哪些对实体这个概念至关重要的行为和属性
-
值标识(可以理解为id)
- 对象是根据值来确定的
- 可以在不同的实体中使用
- 值对象通常是不可变的
-
领域服务
- 领域服务指的是就是实体的某种行为
-
特征
- 服务执行的操作涉及一个领域概念,这个概念通常不属于一个实体或对象
- 被执行的操作涉及到领域中的其他对象
- 操作是无状态的
-
聚合的特定
- 根对象具有值标识
- 外部对象不能直接调用根对象的内部引用对象
聚合的定义有点像是门面模式,将内部功能封装起来
领域对象的管理
创建管理领域对象的生命周期是一个复杂且敏感的功能,介绍3个模式来进行分解
聚合模式
- 聚合是一个用来定义对象所有权和边界的领域模式。工厂和资源库是另外的两个设计模式,用来帮助我们处理对象的创建和存储问题
由于模型间的相互关系依赖,导致实例与实例存在相互引用,在这种情况下很难梳理清楚一个领域对象的关系。
什么是聚合模式?
通过一个实体根对象持有聚合对象的引用,聚合对象之间可以相互依赖。对外只暴露实体根对象,形成以实体根对象为核心内聚的领域对象
聚合是如何保持数据一致性和强化不变量的呢?
因为其他对象只能持有对根对象的引用,这意味着它们不能直接变更聚合内的其他的对象。它们所能做的就是对根做变更,或者让请求根来执行某些动作
工厂模式
领域模式中重点强调使用工厂模式来创建复杂对象
- 工厂被用来封装对象创建所必需的知识,它们对创建聚合特别有用。当聚合的根被创建后,所有聚合包含的对象将随之创建,所有的不变量得到了强化。
因此,为复杂对象和聚合创建实例的职责,应该转交给一个单独的对象。虽然这个对象本身在领域模型中没有职责,但它仍是领域设计的一部分。提供一个接口来封装所有复杂的组装过程,客户不需要引用正在初始化的对象所对应的具体类。将整个聚合当作一个单元来创建,强化它们的不变量。
一个聚合包含了一系列密切相关的对象。根的构建与聚合内的其他对象的创建是相关的。会有一些逻辑一同放到聚合中,这些逻辑并不天然属于任何一个对象,因为它总是跟其他对象的构建有关。看起来比较合适的做法是,使用一个专用的工厂类来负责创建整个聚合,在这个工厂类中将包含应该为聚合强化的规则、约束和不变量。这个对象会保持简单,并将完成特定的目的,不会使复杂的构建逻辑混乱不堪。
ps:也就是有对象创建工厂来专门负责聚合对象的创建工作,将对象的聚合关系的创建全部放到对象创建工厂中去
不使用工厂使用实体构造器的条件
- 构造过程并不复杂。
- 一个对象的创建不涉及到其他对象的创建,可以将所有需要的属性传递给构
造器 - 客户对实现很感兴趣,可能希望选择使用策略(Strategy)模式。
- 类是特定的类型,不存在到层级,所以不用在一系列的具体实现中进行选
择。
第三点,客户端对实体的创建很感兴趣,也就是说对象的创建非常依赖于客户端的行为,此时可以考虑使用策略模式。工厂也可以达到这样的效果,但是需要有标识符传入
资源库
资源库:访问实体的工具,位于领域层和基础实施层之间。作用是通过基础设施层的工具先领域层输出实体对象。
资源库与工厂的区别:资源库关注的是如何将已存在的实体重新载入到领域层中;工厂关心的是如何创建一个新的实体对象。两者一个关注的是已有对象一个关注的是如何创建新对象。
面向深层理解的重构
- 持续重构
- 关注核心模型
模型的一致性
- 边界上下文
- 持续集成
- 上下文映射
- 共享内核
- 客户-供应商
- 顺从者
- 防崩溃层
- 隔离通道
- 开发主机服务
- 提炼