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

在深入支付订单的聚合建模之前,必须重新校准 DDD 中最核心的四个战术模式:实体(Entity)、值对象(Value Object)strong>、聚合(Aggregate) 和 聚合根(Aggregate Root)。这些概念是划分服务边界、设计缓存策略的基石。理解它们的区别与协作关系,决定了后续 Redis 缓存粒度的合理性。

1. 实体(Entity):具有唯一标识且可变的对象

实体拥有一个贯穿生命周期的唯一标识(ID),其属性可以变化,但身份不变。在支付场景中,Order 是一个典型的实体:订单号(OrderId)一旦生成,无论状态如何流转,它始终代表同一笔交易。

  • 核心特征:通过 ID 区分,而非属性值。
  • 可变性:允许修改状态(如从“待支付”变为“已支付”)。
  • 缓存视角:实体通常需要缓存,且缓存键应包含 ID(如 order:12345)。

2. 值对象(Value Object):描述性、不可变且无标识

值对象通过属性值来定义自身,没有唯一标识,且通常是不可变的。两个值对象如果所有属性相同,则视为同一个对象。在支付订单中,Money、Address、PaymentMethod 都是值对象。

  • 核心特征:无 ID,通过属性比较相等。
  • 不可变性:替换而非修改。例如,修改金额应创建新的 Money 对象。
  • 缓存视角:值对象常作为实体的属性被整体缓存,很少单独缓存。
关键区别速查表
维度 实体(Entity) 值对象(Value Object)
唯一标识 有(ID) 无
可变性 可变 不可变
相等性判断 ID 相等 所有属性相等
生命周期 独立存在 依附于实体
缓存粒度 按 ID 缓存 作为实体属性缓存

3. 聚合(Aggregate)与聚合根(Aggregate Root)

聚合是一组相关对象的集群,被视为一个数据修改的一致性边界。聚合根是聚合中唯一的根实体,外部只能通过聚合根来访问聚合内的对象。这保证了数据的一致性和业务不变量的保护。

  • 聚合根:全局唯一标识,负责控制所有对聚合内部对象的访问。
  • 边界:聚合内部的对象不能直接被外部 Repository 引用,必须通过聚合根。
  • 事务范围:一个事务只应修改一个聚合实例。

在支付订单上下文中,Order 作为聚合根,内部包含 OrderItem(实体)、Money(值对象)、PaymentRecord(实体)等。外部系统(如库存服务)不能直接操作 OrderItem,只能通过 Order 聚合根的方法来调整。

支付订单聚合结构示例 聚合边界(事务一致性) Order(聚合根) orderId: String (全局唯一ID) OrderItem(实体) itemId: Long (本地ID) Money(值对象) amount + currency PaymentRecord(实体) transactionId: String 说明:外部服务只能通过 Order 聚合根访问内部对象,保证数据一致性与业务规则不被绕过。

4. 聚合设计原则与缓存策略的关联

聚合的边界设计直接影响 Redis 缓存的粒度和失效策略。以下是几个核心原则及其对缓存的影响:

  1. 原则一:聚合要小 —— 只包含必须保持一致的属性。过大的聚合会导致缓存对象臃肿,频繁更新时性能下降。
  2. 原则二:通过聚合根访问 —— 缓存键应基于聚合根 ID。例如 order:12345 缓存整个聚合,而非为 OrderItem 单独建缓存。
  3. 原则三:事务只影响一个聚合 —— 更新缓存时,只需失效或更新该聚合对应的缓存键,避免跨聚合的缓存一致性问题。
  4. 原则四:值对象不可变 —— 值对象变化时,直接替换整个聚合的缓存值,无需部分更新。
缓存粒度建议:在支付订单服务中,推荐以聚合根为单位进行缓存。将 Order 聚合整体序列化为 JSON 存入 Redis,键为 order:{orderId}。这样既保证了读取时的一次性获取,也简化了缓存失效逻辑。
聚合根与 Redis 缓存键映射 应用服务 OrderApplicationService 领域层(聚合) Order 聚合根 + OrderItem[] + Money total + PaymentRecord Redis 缓存 Key: order:12345 Value: JSON { orderId, items, total, payment } 调用 缓存/读取 关键点:缓存键直接使用聚合根 ID,缓存内容为整个聚合的序列化快照,保证读取时数据完整。

5. 常见建模误区与避坑指南

误区一:将值对象当作实体缓存
例如,为 Money 对象单独设置缓存键 money:order:12345。这破坏了聚合边界,且值对象不可变,单独缓存无意义。

误区二:聚合过大导致缓存失效频繁
将整个订单、用户、物流信息放入一个聚合。任何子属性的变化都会导致整个大缓存失效,降低命中率。

误区三:忽略聚合根的直接缓存
直接缓存内部实体(如 OrderItem)而绕过聚合根,导致数据不一致。应始终以聚合根为缓存入口。

6. 小结:概念回顾与缓存策略的衔接

实体、值对象、聚合和聚合根构成了 DDD 战术建模的骨架。在支付订单服务中:

  • 实体(Order, OrderItem)提供唯一标识,适合按 ID 缓存。
  • 值对象(Money, Address)作为属性嵌入,无需独立缓存。
  • 聚合根(Order)定义了一致性边界,是缓存的最小单元。
  • 缓存策略:以聚合根 ID 为键,序列化整个聚合为值,实现高内聚、低耦合的缓存设计。