2. 领域驱动设计基础回顾:实体、值对象、领域服务、领域事件的核心定义
在深入聚合根与微服务边界之前,必须重新校准 DDD 战术模式的四个基本构造块。它们不仅是建模语言,更是微服务拆分时判断“该不该独立成一个服务”的底层依据。
2.1 实体(Entity)—— 拥有身份标识与连续生命周期的对象
实体是 DDD 中最核心的概念。一个实体具备唯一标识,并且这个标识在其整个生命周期中保持不变。判断一个对象是否为实体,不取决于它的属性值,而取决于它是否拥有一个不可变的 ID。
| 特征 | 说明 | 典型示例 |
|---|---|---|
| 唯一标识 | 通过 ID(UUID、自增主键、业务编号)区分不同实例 | 用户ID、订单ID、聚合根ID |
| 可变性 | 属性可以修改,但身份不变 | 用户修改昵称,仍是同一个用户 |
| 生命周期 | 从创建到持久化再到归档,身份持续存在 | 订单从待支付到已完成 |
| 相等性 | 通过 ID 比较,而非属性值 | 两个同名用户,ID不同则不同实体 |
建模提示: 在微服务拆分时,实体通常对应数据库中的主表,且其 ID 是跨服务通信时唯一可用的引用句柄。如果一个对象没有独立生命周期,不要强行建模为实体。
2.2 值对象(Value Object)—— 描述性、不可变、无身份
值对象描述领域的某个度量或描述,它没有概念上的身份标识,其相等性完全基于所有属性的值。值对象一旦创建就不可变,修改即替换。
- 无身份: 两个“金额 100 元、币种人民币”的值对象,就是同一个值对象。
- 不可变: 修改地址不是修改原对象,而是创建新地址对象替换引用。
- 自包含: 值对象内部可以包含其他值对象或实体引用,但整体无独立生命周期。
- 可共享: 同一个值对象实例可以被多个实体安全共享。
| 对比维度 | 实体 | 值对象 |
|---|---|---|
| 身份标识 | 有(ID) | 无 |
| 可变性 | 可变 | 不可变 |
| 相等性 | ID 相等 | 所有属性相等 |
| 生命周期 | 独立 | 依附于实体 |
| 数据库存储 | 独立表 | 内嵌或序列化 |
微服务映射: 值对象通常作为实体的属性内嵌存储,不单独建表。在服务间传输时,值对象以不可变 DTO 形式传递,天然适合事件溯源中的快照。
2.3 领域服务(Domain Service)—— 无状态、跨实体的业务逻辑
当某个业务操作不属于某个实体或值对象的自然职责时,就需要领域服务。领域服务是无状态的,它协调多个领域对象完成一个业务动作。
- 无状态: 不持有自己的数据,只依赖传入的领域对象。
- 行为聚焦: 封装一个完整的业务原子操作。
- 命名规范: 通常以动词或动词短语命名,如
TransferService、FraudDetectionService。 - 与基础设施服务区分: 领域服务只包含业务规则,不涉及数据库、消息队列等基础设施。
常见误区: 不要把所有操作都塞进领域服务。如果一个操作可以自然地放在实体方法中(如
order.calculateTotal()),就不要提取到服务中。领域服务是“最后的手段”,不是“默认选择”。
// 领域服务示例:转账
public class TransferService {
public void transfer(Account from, Account to, Money amount) {
// 领域规则:扣款
from.debit(amount);
// 领域规则:入账
to.credit(amount);
// 领域事件:转账完成
DomainEventPublisher.publish(new TransferCompleted(from.getId(), to.getId(), amount));
}
}
2.4 领域事件(Domain Event)—— 记录已发生的业务事实
领域事件表示领域中已经发生的、对业务有意义的事件。它是 DDD 中实现最终一致性和事件驱动架构的核心机制。
| 属性 | 说明 | 示例值 |
|---|---|---|
| 事件名称 | 过去时态的动词短语 | OrderPlaced |
| 事件 ID | 全局唯一标识 | UUID |
| 发生时间 | 事件产生的时间戳 | 2025-01-15T10:30:00Z |
| 事件数据 | 与事件相关的业务数据 | 订单ID、金额、用户ID |
| 版本号 | 事件 schema 版本 | 1.0 |
微服务价值: 领域事件是微服务之间异步解耦的基石。一个服务发布事件,其他服务订阅并做出反应,无需同步调用。例如:订单服务发布
OrderPaid 事件,库存服务订阅后扣减库存,物流服务订阅后创建发货单。
2.5 四种构造块的关系总结
在领域模型中,这四种构造块协同工作:实体作为身份锚点,值对象作为属性描述,领域服务协调跨实体的业务逻辑,领域事件记录业务事实并驱动后续流程。理解它们的边界,是后续定义聚合根和微服务拆分的前提。
记忆口诀: “实体有身份,值对象无身份;服务管行为,事件记事实。” 在建模时,先识别实体,再填充值对象,遇到跨实体逻辑提取领域服务,最后用领域事件解耦。