DDD
DDD(Domain-Driven Design,领域驱动设计)是"从业务领域出发设计软件"的方法论:核心是先搞清业务领域怎么划分、每个领域里有什么概念和规则,再让代码结构忠实反映领域结构。传统开发从"表结构/接口"倒推设计,DDD 从"业务语言(Ubiquitous Language,统一语言)"正推——业务专家和开发用同一套术语沟通,代码里的类名、方法名就是业务词汇。它解决"业务复杂时软件难以跟上业务变化"的问题,是 微服务 拆分(见限界上下文)与中台建设的常用理论支撑。
核心概念总览
| 概念 | 定义 | 一句话 |
|---|---|---|
| 限界上下文 | 业务边界,一个上下文一套模型与术语 | 拆分的边界依据 |
| 统一语言 | 上下文中团队共享的业务术语 | 代码=业务词汇 |
| 实体 Entity | 有唯一标识、状态可变的对象 | 有 ID 的东西 |
| 值对象 VO | 无标识、不可变、靠值相等 | 描述性概念 |
| 聚合 Aggregate | 一组实体+值对象的业务组合 | 一致性边界 |
| 聚合根 | 聚合的入口,外部只能通过它操作 | 聚合的门面 |
| 仓储 Repository | 聚合的持久化抽象 | 存取的接口 |
| 领域事件 | 领域中已发生的事实 | 异步解耦的信号 |
限界上下文与微服务
限界上下文是 DDD 与 微服务 的接合点:一个限界上下文通常映射为一个微服务。划分依据是"业务能力与语言边界",而非技术层:
| 划分维度 | 示例 |
|---|---|
| 按业务能力 | 订单上下文、库存上下文、支付上下文(各自独立演进) |
| 按语言边界 | "客户"在销售上下文是"买家",在售后上下文是"投诉人"——不同模型 |
| 按变化频率 | 高频变更的核心上下文 vs 稳定支撑上下文 |
划分信号
同一术语在不同部门含义不同、或一个概念被两个团队以不同方式修改时,就是限界上下文的边界。上下文间通过防腐层(Anti-Corruption Layer)翻译模型,避免一个上下文的概念污染另一个(详见 微服务 的拆分方法论)。
实体 vs 值对象
| 维度 | 实体 Entity | 值对象 Value Object |
|---|---|---|
| 标识 | 有唯一 ID(id 相同即同一对象) | 无 ID,靠所有属性相等 |
| 可变性 | 可变(状态随生命周期变化) | 不可变(替换而非修改) |
| 生命周期 | 有(创建-变更-删除) | 无(依附于实体) |
| 示例 | 订单 Order、用户 User | 金额 Money、地址 Address |
public class Order { // 实体:有 ID、状态变化
private Long id;
private OrderStatus status;
private Money totalAmount; // 值对象:金额
public void markPaid(Money amount) {
this.totalAmount = amount;
this.status = OrderStatus.PAID;
}
}
public record Money(BigDecimal amount, String currency) { } // 值对象:不可变值对象的价值
把"金额+币种""地址"等建模成值对象,避免魔法数字与散落的重复逻辑——Money 的金额计算、币种校验集中在值对象内,实体保持精简。值对象"不可变"保证共享安全。
聚合与聚合根
聚合是一组必须保持一致性的对象集合,聚合根是外部访问的唯一入口。例如"订单聚合"= 订单(根)+ 订单项(实体)+ 金额(值对象):下单、修改、取消都通过订单根操作,订单项不能脱离订单单独修改。
public class Order { // 聚合根
private List<OrderItem> items; // 聚合内实体
public void addItem(OrderItem item) { // 外部只能通过根操作
if (this.status != OrderStatus.CREATED) throw new IllegalStateException();
items.add(item);
}
}| 聚合设计原则 | 说明 |
|---|---|
| 一致性边界 | 聚合内强一致,聚合间最终一致 |
| 根是入口 | 外部引用只能指向聚合根 |
| 尽量小 | 聚合越大并发冲突越多,倾向小聚合 |
| 跨聚合用领域事件 | 不直接改其他聚合的内部 |
领域服务、仓储与领域事件
// 领域服务:跨越多个聚合的业务逻辑(如"创建订单并扣库存")
@Service
public class OrderDomainService {
public void createOrder(Order order, Stock stock) {
order.create();
stock.deduct(order.getTotalQuantity()); // 跨聚合操作
}
}
// 仓储:聚合的持久化接口(实现层用 JPA/MyBatis 落地)
public interface OrderRepository {
Order findById(Long id);
void save(Order order);
}
// 领域事件:下单完成 -> 发布事件,通知其他上下文
order.publishEvent(new OrderCreatedEvent(order.getId()));分层映射
DDD 四层——接口层(Controller)、应用层(用例编排)、领域层(实体/服务/仓储接口)、基础设施层(数据库/消息实现)。领域层是最核心且不依赖任何框架的层;应用分层 的 DO/DTO/VO 与此对应:领域对象在领域层,DTO 是接口层的传输对象。
战术与战略设计
| 层面 | 解决什么 | 工具 |
|---|---|---|
| 战略设计 | 领域怎么划分、边界在哪 | 限界上下文、上下文映射、统一语言 |
| 战术设计 | 上下文内部怎么建模 | 实体/值对象/聚合/仓储/领域事件/领域服务 |
战略设计决定"拆成什么服务",战术设计决定"服务内部怎么组织"。实践中多数团队只做战略设计(划边界)就收益明显,战术设计全量落地成本高,按核心上下文取舍。
DDD 与 微服务 的拆分方法论(限界上下文)、应用分层 的层次架构、设计模式 的领域建模模式(仓储=门面/适配器)相互支撑,是复杂业务架构设计的核心理论。