深入理解 DDD(领域驱动设计)思想
前言
在复杂业务系统的开发中,我们常常会遇到以下问题:
- 业务逻辑越来越复杂,代码越来越混乱;
- 不同模块间高度耦合,修改一个地方牵一发而动全身;
- 技术和业务沟通存在“语言鸿沟”,产品和开发理解不一致。
为了解决这些问题,Eric Evans 在 2003 年提出了一个思想体系 —— DDD(Domain-Driven Design,领域驱动设计)。
它的核心目标是:让软件设计真正贴合业务领域,并通过模型实现业务的可理解性与可演化性。
一、什么是领域驱动设计(DDD)
DDD 的核心思想是:
让领域(Domain)成为系统设计和实现的中心,通过模型驱动代码的结构。
换句话说,不再以数据库表、API 接口、框架结构来主导设计,而是以业务模型为中心组织代码。
DDD 将系统划分为以下几个重要概念:
概念 | 含义 |
---|---|
领域(Domain) | 问题空间,即业务本身,如“订单”、“库存”、“用户”等。 |
子领域(Subdomain) | 业务中可分解的子问题区域,如订单系统中的“支付子域”、“物流子域”。 |
限界上下文(Bounded Context) | 模型的边界,一个上下文中模型的含义是唯一的。 |
领域模型(Domain Model) | 对业务概念、规则、行为的抽象建模,是系统的灵魂。 |
二、DDD 的分层架构
在实现层面,DDD 通常采用四层架构(也称“分层领域架构”):
- 用户接口层 (UI)
- 应用层 (Application)
- 领域层 (Domain)
- 基础设施层 (Infrastructure)
各层职责说明:
层级 | 职责 |
---|---|
UI层 | 与用户交互(如Controller、API)。 |
应用层 | 负责业务流程编排,不包含业务逻辑。 |
领域层 | 业务核心逻辑的所在地(聚合、实体、值对象、领域服务)。 |
基础设施层 | 提供技术支持(数据库、消息队列、外部接口)。 |
三、DDD 的核心构建块
DDD 提供了一系列“战术设计模式”(Tactical Design),用来帮助我们在代码中实现领域模型:
1. 实体(Entity)
- 具有唯一标识(ID),生命周期可变;
业务中同一个实体可在不同时间点有不同状态。
public class Order { private Long id; private OrderStatus status; private List<OrderItem> items; public void pay() { if (status != OrderStatus.CREATED) { throw new IllegalStateException("订单状态不合法"); } this.status = OrderStatus.PAID; } }
2. 值对象(Value Object)
- 没有唯一标识;
- 不可变;
- 用于描述属性或小的概念模型。
public record Money(BigDecimal amount, String currency) {
}
3. 聚合与聚合根(Aggregate / Aggregate Root)
- 聚合是一个业务一致性边界;
- 聚合根是外部访问聚合的唯一入口。
public class OrderAggregate {
private Order order;
private List<OrderItem> items;
public void addItem(OrderItem item) {
// 保证聚合内业务规则一致
items.add(item);
}
}
4. 领域服务(Domain Service)
当业务逻辑无法自然归属到某个实体或值对象时,放在领域服务中;
强调“业务含义”,不是“技术服务”。
public class PaymentService {
public void pay(Order order, PaymentMethod method) {
// 执行支付领域逻辑
}
}
四、总结
DDD 是一种思想,不是框架,也不是银弹。
它强调的是:
以业务为中心设计系统,让代码成为业务知识的载体。
在系统复杂度不断提升的今天,DDD 能帮助团队:
- 统一语言;
- 明确边界;
- 优化架构;
- 让系统具备可演化性。