2. 领域驱动设计基础:实体、值对象、聚合、聚合根的概念回顾

在进入支付订单系统的聚合建模之前,必须重新校准 DDD 战术设计中的四个核心概念:实体(Entity)、值对象(Value Object)strong>、聚合(Aggregate) 和 聚合根(Aggregate Root)。支付领域对数据一致性、不可变性和边界划分有极高要求,理解这些概念的精确含义是后续建模的基石。

2.1 实体(Entity)—— 拥有身份标识的对象

实体最核心的特征是 唯一标识。两个实体即使所有属性值都相同,只要标识不同,就是两个不同的对象。实体的状态可以随时间变化,但标识终身不变。

特征 说明 支付系统示例
唯一标识 每个实体拥有不可变的 ID(如 UUID、业务流水号) 订单 ID、支付单 ID、商户 ID
可变状态 属性可随时间变化,但标识不变 订单状态从“待支付”变为“已支付”
相等性 通过标识判断相等,而非属性值 两个订单对象只要 orderId 相同即为同一订单
生命周期 从创建到归档,标识始终存在 支付单从创建到结算完成
支付系统关键实体清单: 订单(Order)、支付单(Payment)、商户(Merchant)、用户账户(Account)、退款单(Refund)。每个实体都必须有全局唯一的业务标识。

2.2 值对象(Value Object)—— 描述性、不可变、无标识

值对象描述事物的 属性或度量,没有独立标识,通过所有属性值判断相等性。一旦创建就不可变,需要修改时直接替换整个对象。值对象是聚合内降低复杂度的关键工具。

  • 无标识: 两个金额对象(100.00, CNY)就是相等的,不需要 ID。
  • 不可变性: 修改金额时创建新对象,而非修改原对象。
  • 自包含行为: 值对象可以封装业务逻辑,如金额的加法、汇率换算。
  • 可共享: 同一个值对象实例可被多个实体引用。
值对象 属性 支付场景
Money 金额 + 币种 订单金额、支付金额、退款金额
Address 省/市/区/详细地址 商户结算地址、用户收货地址
PaymentMethod 类型 + 卡号后四位 + 有效期 信用卡、支付宝、支付
Period 开始时间 + 结束时间 结算周期、优惠有效期
建模建议: 在支付系统中,优先将“金额”、“费率”、“时间区间”、“卡信息”设计为值对象。这能避免实体泛滥,同时利用不可变性防止并发修改问题。

2.3 聚合(Aggregate)—— 事务一致性的边界

聚合是一组相关对象的 一致性边界。边界内的所有对象在同一个事务中必须保持数据一致。聚合通过聚合根对外暴露操作,外部对象只能通过聚合根引用聚合内的其他对象。

  • 事务边界: 一次提交只修改一个聚合,保证最终一致性。
  • 内部一致性: 聚合内的实体和值对象共同满足业务不变量。
  • 外部引用: 外部只能持有聚合根的 ID,不能直接引用内部对象。
  • 粒度控制: 聚合不宜过大,否则影响并发性能;也不宜过小,否则失去一致性意义。
常见错误: 将整个订单系统设计为一个巨型聚合,导致每次操作锁定大量数据,严重降低吞吐量。支付系统应拆分为订单聚合、支付聚合、结算聚合等独立边界。

2.4 聚合根(Aggregate Root)—— 聚合的唯一入口

聚合根是聚合中 唯一的实体,负责维护聚合内所有对象的一致性。外部对象只能通过聚合根的方法来操作聚合内部。聚合根拥有全局唯一标识,而内部实体只有本地标识。

角色 职责 支付示例
全局标识 聚合根 ID 全局唯一,内部实体 ID 仅在聚合内唯一 支付单 ID(全局) vs 支付明细序号(本地)
一致性守卫 所有修改必须通过聚合根方法,确保不变量不被破坏 支付单聚合根确保“支付金额 ≤ 订单剩余金额”
生命周期管理 聚合根的创建和删除决定整个聚合的生命周期 支付单关闭时,其下的所有支付明细一并失效
持久化入口 Repository 只操作聚合根,级联持久化内部对象 PaymentRepository 保存支付单及其明细

2.5 概念关系全景图

下图展示了四个概念在支付订单上下文中的层级关系与交互方式:

DDD 核心概念关系图 —— 支付订单上下文 聚合:支付单(Payment) 聚合根:Payment ID: pay_20250321001 内部实体:PaymentItem 本地序号: 1, 2, 3 ... 值对象:Money 金额: 199.00 | 币种: CNY 值对象:PaymentMethod 类型: CREDIT_CARD | 尾号: 1234 聚合:订单(Order) 聚合根:Order ID: ord_20250321001 内部实体:OrderLine 商品ID | 数量 | 单价 值对象:Money 总金额: 199.00 | 币种: CNY 值对象:Address 收货地址: 北京市朝阳区... 通过 orderId 引用 关键规则:外部对象只能通过聚合根 ID 引用聚合,不能直接引用内部实体或值对象 一次事务只修改一个聚合,跨聚合一致性通过领域事件 + 最终一致性实现

2.6 支付系统中的聚合划分原则

基于上述概念,支付订单系统的聚合划分应遵循以下原则:

  1. 事务边界最小化: 每个聚合只包含必须保持强一致性的对象。例如,支付单聚合包含支付明细和支付方式,但不包含商品信息。
  2. 聚合根选择: 选择业务生命周期最长、对外暴露最多的实体作为聚合根。支付单(Payment)比支付明细(PaymentItem)更适合作为聚合根。
  3. 值对象优先: 金额、费率、时间区间等无标识概念一律设计为值对象,减少实体数量,提升不可变性带来的并发安全。
  4. 跨聚合通信: 使用领域事件(Domain Event)实现最终一致性,避免跨聚合的直接事务依赖。
支付系统典型聚合划分:
• 订单聚合(Order Aggregate):订单 + 订单行 + 金额值对象
• 支付单聚合(Payment Aggregate):支付单 + 支付明细 + 支付方式值对象
• 结算聚合(Settlement Aggregate):结算单 + 结算明细 + 费率值对象
• 退款聚合(Refund Aggregate):退款单 + 退款明细 + 退款原因值对象