04 DDD领域驱动中聚合根的概念

vvEcho 2025-02-19 18:36:43
Categories: > Tags:

在领域驱动设计中,聚合根(Aggregate Root)的设计原则是什么?在佣金系统的订单管理域重构时,如何通过聚合根设计避免分布式事务?请结合您拆分价保域和订单域的实例说明

  1. 聚合根(Aggregate Root)设计原则‌

    您的回答正确但需补充完整,核心原则包括:‌

    ✅ 强一致性边界:聚合根内的所有实体/值对象必须保持一致性(如订单总金额与子项金额总和一致)。‌

    ✅ 最小化设计:一个聚合根只聚焦一个核心业务目标(如订单聚合根仅关注订单生命周期,价保聚合根聚焦价保规则)。‌

    ✅ 事务边界:单次事务仅修改一个聚合根(避免跨聚合根的ACID事务)。‌

    ✅ 引用方式:跨聚合根通过ID引用(如订单聚合根不直接持有价保对象,而是记录priceProtectionId)。‌

    ✅ 操作入口:外部只能通过聚合根的方法修改内部状态(如调用order.applyPriceProtection()而非直接修改子项价格)。‌
  2. 京东佣金系统实例分析‌

    在您改造的订单管理域与价保域拆分场景中,典型设计如下:‌
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 旧代码:订单服务直接调用价保服务(跨服务事务)
    public class OrderService {
    @Transactional
    public void applyPriceProtection(Order order, PriceProtection policy) {
    // 1. 修改订单金额
    order.updateAmount(policy.getDiscount());
    // 2. 调用价保服务记录状态
    priceProtectionService.lockPolicy(policy.getId());
    // 若此处价保服务调用失败,需回滚订单修改(分布式事务难题)
    }
    }
    改造后拆分了订单域和价保域‌
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // 订单聚合根方法
    public class Order {
    public void applyPriceProtection(BigDecimal discount) {
    // 仅修改订单金额(不依赖外部状态)
    this.totalAmount = this.totalAmount.subtract(discount);
    // 发布领域事件
    DomainEventPublisher.publish(new PriceProtectionAppliedEvent(this.id, discount));
    }
    }

    // 价保聚合根监听事件
    public class PriceProtectionEventHandler {
    @Subscribe
    public void handle(PriceProtectionAppliedEvent event) {
    PriceProtection policy = repository.findById(event.getPolicyId());
    policy.markAsUsed(); // 标记价保规则已使用(最终一致性)
    }
    }
    3.通过ID实现跨聚合引用‌
    1
    2
    3
    4
    5
    // 订单聚合根记录价保ID(非直接引用对象)
    public class Order {
    private String id;
    private List<String> appliedPriceProtectionIds; // 价保ID列表
    }