文章目录
概念
DDD(domain-driven design)(领域驱动设计)。
特点:
以业务为中心,强调开发和业务必须使用同一套术语,即通用语言。
模型分层和核心构件
| 核心构件 | 作用与特点 |
|---|---|
| 实体 | 具有唯一标识的对象(如订单ID),它的状态会随时间变化(如订单状态从"待支付"变为"已发货")。 |
| 值对象 | 没有唯一标识,仅描述事物的属性(如"收货地址"、“金额”)。它是不可变的,用完即弃,更轻量、更安全。 |
| 聚合根(充血实体) | 一组相关对象的"门面"或"入口"。外部访问聚合内的任何对象,都必须通过聚合根,这确保了数据的一致性。 |
| 领域服务 | 处理一些不适合放在实体里的业务逻辑,比如"转账"这种涉及多个账户的操作。 |
订单业务示例
1. 值对象 (Value Object)
DDD原则:把经常绑在一起的数据打包,用对象代替散落的字段。
// 金额是一个值对象,它有自己的业务规则(比如不能为负数)
@Getter
@AllArgsConstructor
public class Money {
private BigDecimal amount;
public Money(BigDecimal amount) {
if (amount.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("金额不能为负数");
}
this.amount = amount;
}
}
2. 领域事件 (Domain Event)
DDD 原则:实体只负责自己的状态变更,不关心后续要做什么(解耦)。
// 记录“订单已支付”这个事实
@Getter
@AllArgsConstructor
public class OrderPaidEvent {
private Long orderId;
private Money paidAmount;
}
3. 充血实体 / 聚合根 (Aggregate Root)
DDD原则:没有 Setter!只有业务方法。把校验逻辑锁死在内部。
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 私有构造,防止外部随意 new
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Enumerated(EnumType.STRING)
private OrderStatus status; // 使用枚举,告别魔法数字
private BigDecimal totalAmount;
// 忽略 JPA 持久化,仅用于内存中暂存事件
@Transient
private List<Object> domainEvents = new ArrayList<>();
// 工厂方法:创建订单
public static Order create(BigDecimal totalAmount) {
Order order = new Order();
order.totalAmount = totalAmount;
order.status = OrderStatus.PENDING_PAYMENT;
return order;
}
// 【核心业务行为】:支付订单
public void pay(Money payAmount) {
// 1. 状态校验(强一致性)
if (this.status != OrderStatus.PENDING_PAYMENT) {
throw new BusinessException("订单当前状态不允许支付");
}
// 2. 金额校验
if (this.totalAmount.compareTo(payAmount.getAmount()) != 0) {
throw new BusinessException("支付金额与订单金额不符");
}
// 3. 状态流转
this.status = OrderStatus.PAID;
// 4. 注册领域事件(告诉外界:我支付完了,你们看着办)
this.domainEvents.add(new OrderPaidEvent(this.id, payAmount));
}
}
4. 仓储接口 (Repository)
DDD原则:领域层定义接口,基础设施层去实现(隔离数据库)。
// 只需要暴露聚合根的操作
public interface OrderRepository {
Order findById(Long id);
void save(Order order);
}
5. 应用服务 (Application Service)
DDD原则:不含任何 if-else!只做“查出实体 -> 调用方法 -> 保存 -> 发事件”的流水线工作。
@Service
public class OrderAppService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private ApplicationEventPublisher eventPublisher; // Spring 的事件发布器
public void payOrder(Long orderId, BigDecimal amount) {
// 1. 获取聚合根
Order order = orderRepository.findById(orderId);
// 2. 调用充血实体的业务方法(Service 完全不知道支付规则是什么)
order.pay(new Money(amount));
// 3. 持久化
orderRepository.save(order);
// 4. 发布领域事件(自动触发下游业务)
// 把实体内存中积攒的事件拿出来发布
// 这里简化处理,直接发布
eventPublisher.publishEvent(new OrderPaidEvent(orderId, new Money(amount)));
}
}
6. 事件监听器 (Event Listener)
DDD原则:后续动作(发短信、扣积分)完全独立,随时可以增删。
@Component
public class OrderEventHandler {
// 监听订单支付成功事件
@EventListener
public void onOrderPaid(OrderPaidEvent event) {
System.out.println("【积分服务】:用户支付成功,订单号:" + event.getOrderId() + ",增加 100 积分!");
System.out.println("【短信服务】:用户支付成功,发送短信通知...");
}
}

685

被折叠的 条评论
为什么被折叠?



