领域驱动设计基础:实体、值对象、聚合、聚合根的概念回顾
在深入支付订单的聚合建模之前,必须重新校准 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 聚合根的方法来调整。
4. 聚合设计原则与缓存策略的关联
聚合的边界设计直接影响 Redis 缓存的粒度和失效策略。以下是几个核心原则及其对缓存的影响:
- 原则一:聚合要小 —— 只包含必须保持一致的属性。过大的聚合会导致缓存对象臃肿,频繁更新时性能下降。
- 原则二:通过聚合根访问 —— 缓存键应基于聚合根 ID。例如
order:12345缓存整个聚合,而非为OrderItem单独建缓存。 - 原则三:事务只影响一个聚合 —— 更新缓存时,只需失效或更新该聚合对应的缓存键,避免跨聚合的缓存一致性问题。
- 原则四:值对象不可变 —— 值对象变化时,直接替换整个聚合的缓存值,无需部分更新。
缓存粒度建议:在支付订单服务中,推荐以聚合根为单位进行缓存。将
Order 聚合整体序列化为 JSON 存入 Redis,键为 order:{orderId}。这样既保证了读取时的一次性获取,也简化了缓存失效逻辑。
5. 常见建模误区与避坑指南
误区一:将值对象当作实体缓存
例如,为
误区二:聚合过大导致缓存失效频繁
将整个订单、用户、物流信息放入一个聚合。任何子属性的变化都会导致整个大缓存失效,降低命中率。
误区三:忽略聚合根的直接缓存
直接缓存内部实体(如
例如,为
Money 对象单独设置缓存键 money:order:12345。这破坏了聚合边界,且值对象不可变,单独缓存无意义。误区二:聚合过大导致缓存失效频繁
将整个订单、用户、物流信息放入一个聚合。任何子属性的变化都会导致整个大缓存失效,降低命中率。
误区三:忽略聚合根的直接缓存
直接缓存内部实体(如
OrderItem)而绕过聚合根,导致数据不一致。应始终以聚合根为缓存入口。
6. 小结:概念回顾与缓存策略的衔接
实体、值对象、聚合和聚合根构成了 DDD 战术建模的骨架。在支付订单服务中:
- 实体(Order, OrderItem)提供唯一标识,适合按 ID 缓存。
- 值对象(Money, Address)作为属性嵌入,无需独立缓存。
- 聚合根(Order)定义了一致性边界,是缓存的最小单元。
- 缓存策略:以聚合根 ID 为键,序列化整个聚合为值,实现高内聚、低耦合的缓存设计。