在传统的三层架构中,我们习惯将系统划分为 Controller、Service 和 Repository 层,关注点更多落在“技术职责”而非“业务语义”。然而,随着系统复杂度提高,贫血模型、重复逻辑、脆弱耦合等问题层出不穷。
领域驱动设计(DDD) 正是为了解决这些问题而生。它强调以业务为中心建模,将“业务行为”作为核心驱动软件设计,帮助系统在演进中保持稳定性与可维护性。
本文通过电商案例,揭示如何从贫血模型迁移到富领域模型,并实现领域事件驱动架构。
// 典型贫血模型示例
public class Order {
private Long id;
private String status;
private BigDecimal amount;
// 仅有getter/setter,无业务行为
}
@Service
public class OrderService {
@Transactional
public void payOrder(Long orderId) {
Order order = orderRepository.findById(orderId);
// 核心业务逻辑分散在Service层
if (!"CREATED".equals(order.getStatus())) {
throw new IllegalStateException("订单状态异常");
}
Payment payment = paymentClient.pay(order.getAmount());
order.setStatus("PAID");
orderRepository.save(order); // 仅仅是数据更新
}
}
✅ 统一语言:业务与开发共享领域模型词汇
✅ 边界控制:通过聚合划分业务一致性边界
✅ 领域聚焦:业务规则内聚在领域对象中
埃里克·埃文斯在《领域驱动设计》中强调:"模型是系统的核心",贫血模型背离了这一基本原则
典型误用场景:
修正方案:
// 订单聚合根示例
public class Order extends AbstractAggregateRoot<Order> {
private OrderId id;
private Money totalAmount;
private List<OrderItem> items = new ArrayList<>();
private OrderStatus status;
// 业务方法封装在聚合根中
public void addItem(Product product, int quantity) {
// 业务规则内聚
if (this.status != OrderStatus.CREATED) {
throw new DomainException("订单状态异常");
}
OrderItem item = new OrderItem(product, quantity);
this.items.add(item);
this.totalAmount = this.totalAmount.add(item.getSubTotal());
}
// 事件触发点
public void pay() {
this.status = OrderStatus.PAID;
registerEvent(new OrderPaidEvent(this.id));
}
}
// 订单项作为内部实体(非聚合根)
public class OrderItem {
private ProductId productId;
private int quantity;
private Money price;
}
陷阱提示:大聚合(如用户聚合包含订单历史)会导致并发冲突和性能问题,需按业务变化频率拆分
类型 | 职责 |
---|---|
应用服务 | 协调多个聚合根、处理事务、DTO 转换、权限控制等 |
领域服务 | 封装跨聚合的业务逻辑,避免逻辑污染实体或聚合根 |
public class OrderCalculationService {
// 封装复杂价格计算策略(领域服务)
public Money calculateTotal(List<OrderItem> items, DiscountPolicy policy) {
Money total = items.stream()
.map(OrderItem::getSubTotal)
.reduce(Money.ZERO, Money::add);
return policy.applyDiscount(total);
}
}
@Service
@RequiredArgsConstructor
public class OrderAppService {
private final OrderRepository orderRepository;
private final PaymentClient paymentClient; // 外部依赖
private final DomainEventPublisher publisher;
@Transactional
public void payOrder(OrderId orderId) {
Order order = orderRepository.findById(orderId);
order.pay(); // 调用领域行为
// 基础设施调用
PaymentResponse response = paymentClient.execute(order.getTotal());
order.confirmPayment(response);
orderRepository.save(order);
publisher.publishEvents(order); // 发布领域事件
}
}
// 命令模型(写)
@Aggregate
public class OrderAggregate {
@AggregateIdentifier
private OrderId id;
@CommandHandler
public OrderAggregate(CreateOrderCommand command) {
apply(new OrderCreatedEvent(command.getOrderId()));
}
@EventSourcingHandler
public void on(OrderCreatedEvent event) {
this.id = event.getOrderId();
}
}
// 查询模型(读)
@Component
public class OrderProjection {
private final OrderViewRepository repository;
@EventHandler
public void on(OrderCreatedEvent event) {
repository.save(new OrderView(event.getOrderId()));
}
}
// 最终一致性实现(事件传播)
@Configuration
public class EventConfig {
@Bean
public EventStorageEngine storageEngine(DataSource dataSource) {
return JdbcEventStorageEngine.builder()
.dataSource(dataSource)
.build();
}
}
@Component
@ProcessingGroup("payment")
public class PaymentHandler {
@EventHandler
public void handle(OrderPaidEvent event) {
// 调用支付外部系统(非阻塞)
paymentClient.confirm(event.getOrderId());
}
// 事件重试策略
@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000))
public void handlePaymentFailure() {...}
}
// 防腐层接口(领域定义)
public interface PaymentProvider {
PaymentResponse process(PaymentCommand command);
}
// 适配器实现(基础设施层)
@Primary
public class AlipayAdapter implements PaymentProvider {
private final AlipayClient client;
public PaymentResponse process(PaymentCommand command) {
// 将领域命令转为外部系统DTO
AlipayRequest request = convert(command);
AlipayResponse response = client.execute(request);
// 将外部响应转为领域对象
return convert(response);
}
}
// 领域内使用方法
@Service
@RequiredArgsConstructor
public class PaymentService {
private final PaymentProvider provider; // 依赖抽象
public void executePayment(Order order) {
PaymentCommand command = createCommand(order);
PaymentResponse response = provider.process(command);
order.handlePayment(response); // 领域行为
}
}
⚠️ 聚合设计过大:导致并发冲突
✅ 解方:根据业务变更频率拆分聚合
⚠️ 事件风暴脱离业务:成为纯技术讨论
✅ 解方:强制业务方参与工作坊
⚠️ 过度设计防腐层:引入不必要复杂度
✅ 解方:仅在对接易变/不兼容系统时使用
正如Vernon在《实现领域驱动设计》中所说:“好的设计是在过度设计与设计不足之间取得平衡的艺术”