2. 领域驱动设计(DDD)核心概念回顾
领域驱动设计(Domain-Driven Design, DDD)是一套应对复杂业务建模的软件方法论。在数据同步与搜索索引场景中,DDD 的五大核心概念——实体、值对象、聚合、领域事件、限界上下文——直接决定了索引结构的设计粒度、同步边界和事件驱动策略。本节逐一回顾这些概念,并给出与搜索索引映射的对照关系。
2.1 实体(Entity)
实体是具有唯一标识且生命周期持续变化的对象。两个实体即使所有属性相同,只要标识不同,就是不同的对象。在搜索索引中,实体通常对应索引文档的 _id 字段。
| 特征 | 说明 | 索引映射示例 |
|---|---|---|
| 唯一标识 | ID 不可变,贯穿整个生命周期 | Elasticsearch 文档 _id |
| 可变属性 | 状态、名称、金额等可被修改 | 索引中可更新的字段 |
| 相等性 | 通过 ID 判断,而非属性值 | 同步时以 ID 作为主键匹配 |
索引设计提示: 实体在索引中通常作为根文档存在。例如“订单”实体在索引中就是一个独立的 order 文档,其 ID 与数据库主键一致。
2.2 值对象(Value Object)
值对象通过属性值来定义自身,没有唯一标识,且通常是不可变的。两个值对象如果所有属性相同,则视为同一个对象。值对象非常适合作为索引中的嵌套对象或扁平化字段。
| 特征 | 说明 | 索引映射示例 |
|---|---|---|
| 无标识 | 不依赖 ID,只依赖属性组合 | 嵌套对象(nested)或扁平字段 |
| 不可变 | 创建后不允许修改,替换即新建 | 索引中直接覆盖旧值 |
| 相等性 | 所有属性值完全相等才视为相同 | 同步时比较全字段决定是否更新 |
典型场景: “地址”是值对象。在索引中,地址通常被展开为
city、district、street 等扁平字段,或使用 nested 类型保留结构。
2.3 聚合(Aggregate)
聚合是数据一致性边界。一个聚合包含一个聚合根(Aggregate Root)和若干实体/值对象。外部只能通过聚合根访问聚合内部。聚合是数据同步的最小原子单元——要么整个聚合一起同步,要么不同步。
同步边界规则: 聚合根 ID 作为索引文档 ID;聚合内部所有变更必须通过聚合根触发;索引更新时,整个聚合文档整体替换,避免部分更新导致数据不一致。
2.4 领域事件(Domain Event)
领域事件是业务领域中发生的、有意义的、已发生的事实。它是事件驱动数据同步的核心载体。当聚合状态发生变化时,聚合根发布领域事件,事件携带变更数据,驱动索引更新。
| 事件属性 | 说明 | 同步场景示例 |
|---|---|---|
| 事件名称 | 业务语义明确的过去时动词 | OrderCreated、OrderShipped |
| 事件时间 | 事件发生的业务时间戳 | 用于索引中 updatedAt 字段 |
| 事件载荷 | 携带变更后的关键数据 | 聚合根 ID + 变更字段 + 新值 |
| 事件版本 | 用于幂等处理和顺序保证 | 防止重复消费导致索引脏数据 |
事件驱动同步流程:
1. 业务操作 → 聚合根状态变更
2. 聚合根发布领域事件(如
3. 事件总线/消息队列接收事件
4. 索引同步消费者消费事件 → 更新 Elasticsearch 文档
1. 业务操作 → 聚合根状态变更
2. 聚合根发布领域事件(如
OrderStatusChanged)3. 事件总线/消息队列接收事件
4. 索引同步消费者消费事件 → 更新 Elasticsearch 文档
2.5 限界上下文(Bounded Context)
限界上下文是 DDD 中最关键的战略设计概念。它划定了模型边界:每个上下文内部有统一的语言(Ubiquitous Language)和独立的模型实现。不同上下文之间通过上下文映射(Context Map)进行集成。
2.6 核心概念对比总结
| 概念 | 有无标识 | 可变性 | 相等性判断 | 索引映射角色 |
|---|---|---|---|---|
| 实体 | 有 | 可变 | ID 相等 | 索引文档根 |
| 值对象 | 无 | 不可变 | 属性全等 | 嵌套/扁平字段 |
| 聚合 | 聚合根有 ID | 整体替换 | 聚合根 ID 相等 | 同步原子单元 |
| 领域事件 | 有事件 ID | 不可变 | 事件 ID 相等 | 同步触发信号 |
| 限界上下文 | 有上下文名称 | 边界固定 | 名称唯一 | 索引数据源边界 |