2. 领域驱动设计基础:DDD核心概念与战略/战术设计概览
领域驱动设计(Domain-Driven Design,DDD)是一套应对复杂软件系统建模的方法论。它强调以业务领域为核心,通过统一语言(Ubiquitous Language)连接业务专家与技术团队,从而指导服务边界划分与接口设计。本章将系统梳理DDD的核心构造块,并区分战略设计与战术设计两个层次。
2.1 核心构造块:实体、值对象、聚合
DDD将模型元素分为若干基础模式,其中实体(Entity)、值对象(Value Object)和聚合(Aggregate)是最关键的三个构造块。
| 概念 | 定义 | 标识特征 | 典型示例 |
|---|---|---|---|
| 实体 | 具有唯一标识、生命周期可追踪的对象 | 拥有ID,属性可变但身份不变 | 用户(userId)、订单(orderId) |
| 值对象 | 描述某种属性或状态,无唯一标识 | 不可变,通过属性值比较相等 | 地址(城市+街道+邮编)、金额(货币+数值) |
| 聚合 | 一组相关对象的集群,外部只能通过聚合根访问 | 有聚合根(一个实体),保证内部一致性 | 订单聚合(订单实体+订单项值对象+收货地址值对象) |
/users/{id}),值对象适合作为请求/响应体中的嵌套属性,聚合则决定了事务边界与数据一致性范围。
2.2 领域服务与领域事件
当某个业务操作无法自然地归属于某个实体或值对象时,应引入领域服务(Domain Service)。领域服务是无状态的,它协调多个聚合或外部资源完成一个业务用例。例如:TransferService.transfer(fromAccount, toAccount, amount)。
领域事件(Domain Event)用于记录领域中发生的、业务人员关心的状态变化。它是实现事件驱动架构和最终一致性的关键。每个领域事件通常包含事件ID、发生时间、事件数据和版本号。
// 领域事件示例(Java风格)
public class OrderSubmittedEvent implements DomainEvent {
private final String eventId;
private final String orderId;
private final LocalDateTime occurredOn;
private final OrderSnapshot orderData;
// 构造函数、getters省略
}
OrderSubmitted、PaymentCompleted。
2.3 战略设计与战术设计概览
DDD将设计活动分为两个层次:战略设计关注宏观的限界上下文(Bounded Context)划分与上下文映射关系;战术设计关注微观的聚合、实体、值对象等构造块的具体实现。
下图展示了战略设计与战术设计在DDD整体流程中的位置与关系:
2.4 战略设计:限界上下文与上下文映射
限界上下文是DDD中最关键的边界概念。它定义了模型应用的显式范围,每个限界上下文内部有独立的统一语言和模型实现。不同上下文之间通过上下文映射建立集成关系,常见的映射模式包括:
- 合作关系(Partnership):两个上下文紧密协作,同步演进。
- 共享内核(Shared Kernel):共享部分模型代码,但保持各自边界。
- 客户-供应商(Customer-Supplier):上游(供应商)决定模型,下游(客户)适配。
- 防腐层(Anti-Corruption Layer):下游通过转换层隔离上游模型的污染。
- 开放主机服务(Open Host Service):上游以API形式暴露服务,下游通过发布语言(Published Language)调用。
2.5 战术设计:聚合与事务边界
战术设计的核心是聚合设计。聚合通过聚合根(Aggregate Root)保证内部对象的一致性,外部只能通过聚合根的方法修改聚合内部状态。设计聚合时应遵循以下原则:
- 小聚合原则:只包含真正需要一致性的对象,避免加载过多数据。
- 通过聚合根访问:禁止外部直接修改聚合内部实体或值对象。
- 一次事务只修改一个聚合:跨聚合的修改应通过领域事件实现最终一致性。
下图展示了一个典型的订单聚合结构及其对外接口映射关系:
2.6 从DDD到API设计治理的桥梁
DDD为API设计治理提供了清晰的决策依据:
- 限界上下文决定API分组与微服务边界。
- 聚合根决定资源路径的根节点与事务边界。
- 值对象决定请求/响应体中的嵌套结构。
- 领域服务决定无状态操作接口(如POST /transfers)。
- 领域事件决定异步消息契约与Webhook格式。