DDD领域驱动
2025/11/10大约 5 分钟
DDD领域驱动开发指南
💡 用通俗话来说,DDD是什么?
想象一下,你要去餐厅吃饭:
传统开发方式:
- 程序员说:"我要创建一个order表,字段有customer_id、food_items、total_price..."
- 厨师说:"我要做菜,需要食材和菜谱..."
- 服务员说:"我要端盘子,需要托盘和菜单..."
- 大家各说各话,最后做出来的系统可能根本不符合实际需求!
DDD的方式:
- 大家先用统一的语言讨论:
- 顾客说:"我想点餐"
- 厨师说:"我负责烹饪"
- 服务员说:"我负责服务"
- 经理说:"我要管理整个餐厅"
- 然后程序员把这些业务概念变成代码:
- 有点餐的Order类
- 有烹饪的Cook类
- 有服务的Waiter类
- 有管理的Manager类
简单说:DDD就是让程序员用业务的语言写代码,让业务人员也能理解代码在说什么!
1. DDD简介
1.1 什么是DDD
领域驱动设计(Domain-Driven Design,DDD)是一种以业务为中心的软件设计方法。核心理念是:让代码反映真实的业务逻辑,而不是技术实现。
1.2 为什么要用DDD?
- 业务对齐:代码直接反映业务需求,避免"技术做一套,业务用另一套"
- 团队协作:业务人员和技术人员用同一种语言沟通
- 易于维护:业务规则清晰,代码结构自然
- 应对复杂:当业务复杂时,DDD能帮助管理复杂性
1.3 什么时候用DDD?
✅ 适合:
- 业务逻辑复杂(如金融、医疗、电商)
- 需要长期维护和演进
- 多个团队协作开发
- 涉及企业核心业务
❌ 不适合:
- 简单的CRUD应用
- 一次性项目
- 业务逻辑很明确的系统
2. DDD核心概念
2.1 统一语言(Ubiquitous Language)
业务和技术人员都用的共同语言
- 不统一:程序员说"创建user对象",业务说"注册用户"
- 统一后:大家都说"用户注册"
实际例子:
// 业务语言:用户下订单
public class Order {
public void placeOrder(User user, List<Product> products) {
// 业务规则:检查库存
checkInventory(products);
// 业务规则:计算总价
calculateTotal(products);
// 业务规则:创建订单
createOrder(user, products);
}
}2.2 限界上下文(Bounded Context)
把复杂系统分成小块,每块有自己的规则
想象一个大公司:
- 销售部门:关心客户、订单、业绩
- 财务部门:关心收入、成本、报表
- 人事部门:关心员工、考勤、工资
每个部门就是 一个限界上下文,有自己的业务语言和规则。
2.3 领域、子域
- 领域:整个业务范围(如"电商")
- 子域:领域中的具体部分(如"订单"、"支付"、"用户")
- 核心域:最重要的部分(通常是公司的核心竞争力)
3. DDD核心构件
3.1 实体(Entity)
有唯一身份的对象
public class User {
private UserId id; // 唯一标识
private String name;
private String email;
// 即使姓名、邮箱变了,还是同一个用户
public void updateProfile(String name, String email) {
this.name = name;
this.email = email;
// 依然是同一个User,只是属性变了
}
}3.2 值对象(Value Object)
通过属性值来定义,没有唯一身份
public class Money {
private final BigDecimal amount;
private final Currency currency;
// 100元和另一个100元是相等的,可以互换
public Money add(Money other) {
// 实现逻辑
}
}3.3 聚合(Aggregate)
相关对象的组合,外部只能通过"聚合根"访问
// 订单聚合,Order是聚合根
public class Order {
private OrderId id;
private List<OrderItem> items; // 内部对象
// 外部只能通过Order来访问OrderItem
public void addItem(Product product, int quantity) {
OrderItem item = new OrderItem(product, quantity);
items.add(item);
}
}3.4 领域服务(Domain Service)
跨聚合的业务逻辑
public class OrderService {
// 这个逻辑涉及订单和库存两个聚合
public void processOrder(OrderId orderId, InventoryService inventory) {
Order order = orderRepository.find(orderId);
inventory.reserveStock(order.getItems());
order.confirm();
}
}3.5 领域事件(Domain Event)
领域中发生的事情
public class OrderConfirmedEvent {
private OrderId orderId;
private CustomerId customerId;
private Instant confirmedAt;
}
// 订单确认后触发其他业务
public class OrderEventHandler {
public void handle(OrderConfirmedEvent event) {
emailService.sendConfirmation(event.getCustomerId());
inventoryService.reserveStock(event.getOrderId());
}
}4. 分层架构
┌─────────────────────┐
│ 表示层 (UI) │ ← 用户界面
├─────────────────────┤
│ 应用层 (Application)│ ← 协调业务用例
├─────────────────────┤
│ 领域层 (Domain) │ ← 业务逻辑(核心!)
├─────────────────────┤
│ 基础设施层 (Infra) │ ← 数据库、外部服务
└─────────────────────┘重点:领域层是核心,不依赖其他层!
5. 实践建议
5.1 开始DDD的步骤
- 和业务专家一起建模:不要自己闷头设计
- 找到限界上下文:把大系统分成小系统
- 建立统一语言:统一业务和技术术语
- 从小范围开始:选一个核心域先做
- 迭代改进:随着理解深入不断调整
5.2 常见误区
❌ 误区1:把DDD当成技术框架
- DDD是设计方法,不是具体技术
❌ 误区2:过度设计
- 简单业务不需要用DDD
❌ 误区3:只学概念不改思维
- 要真正从业务角度思考问题
5.3 成功要素
✅ 业务专家参与:必须有真正的业务人员
✅ 团队学习:DDD需要时间学习和实践
✅ 迭代演进:不可能一开始就设计完美
✅ 工具支持:需要支持DDD的开发工具
6. 总结
DDD的核心理念是:让代码反映业务,而不是技术实现。
关键要点:
- 建立业务和技术之间的桥梁
- 用业务语言写代码
- 把复杂系统分解成小的限界上下文
- 让每个部分都清晰明了
记住:DDD不是银弹,它适合复杂业务。对于简单项目,可能过度了。选择合适的设计方法才是最重要的!
DDD的学习需要时间,但一旦掌握,能显著提升处理复杂业务的能力。建议从小项目开始实践,逐步掌握这种方法论。