2. 领域驱动设计(DDD)基础回顾:实体、值对象、聚合、聚合根、领域事件、限界上下文
在深入支付订单系统的聚合建模之前,必须重新梳理领域驱动设计的核心战术构件。这些概念不仅是理论标签,更是指导代码结构与业务边界划分的实操工具。本章将结合支付场景,逐一拆解六大核心要素。
2.1 实体(Entity)与值对象(Value Object)
实体拥有唯一的身份标识(ID),其状态会随时间变化,但标识保持不变。在支付系统中,Order、Payment、Account 都是典型的实体。
值对象没有身份标识,通过其属性值来定义相等性,且通常是不可变的。例如:Money、Address、PaymentMethod。
| 维度 | 实体(Entity) | 值对象(Value Object) |
|---|---|---|
| 身份标识 | 有(如 orderId) | 无 |
| 可变性 | 可变(状态可更新) | 不可变(替换而非修改) |
| 相等性判断 | 通过 ID 判断 | 通过所有属性值判断 |
| 支付示例 | 订单、支付单、商户 | 金额、币种、支付渠道编码 |
实践建议:在支付订单模型中,将
Money 设计为值对象,包含 amount 和 currency 两个属性,避免直接使用基本类型 BigDecimal 导致语义丢失。
2.2 聚合(Aggregate)与聚合根(Aggregate Root)
聚合是一组相关对象的集合,被视为数据修改的原子单元。外部对象只能引用聚合根,不能直接操作聚合内部的实体或值对象。聚合根是聚合中唯一允许被外部访问的实体,负责维护聚合内部的不变规则。
在支付订单系统中,一个典型的聚合是 订单聚合:
- 聚合根:
Order(订单实体) - 内部实体:
OrderItem(订单项,有行号标识) - 值对象:
Money(金额)、ShippingAddress(收货地址)
常见误区:将数据库的外键关联直接映射为聚合间的引用。正确的做法是聚合根之间通过全局唯一标识(ID)引用,而非对象引用,以保证聚合边界的独立性。
2.3 领域事件(Domain Event)
领域事件是领域中发生的、业务人员关心的、具有业务意义的事件。它用于在聚合之间或限界上下文之间传递状态变更通知,实现最终一致性。
支付系统中的典型领域事件:
OrderPlaced(订单已提交)PaymentCompleted(支付已完成)PaymentFailed(支付失败)OrderShipped(订单已发货)
关键原则:领域事件是不可变的,通常使用过去时态命名(如
PaymentSucceeded),并包含事件发生时的上下文数据(如订单ID、金额、时间戳)。
2.4 限界上下文(Bounded Context)
限界上下文是 DDD 中最宏观的战略设计工具。它定义了模型应用的边界,每个上下文内部有统一的语言(Ubiquitous Language),且模型的含义在该边界内是自洽的。
在支付系统中,典型的限界上下文划分:
| 限界上下文 | 核心职责 | 聚合根示例 |
|---|---|---|
| 订单上下文 | 订单创建、商品管理、状态流转 | Order |
| 支付上下文 | 支付请求、渠道路由、对账 | Payment |
| 账户上下文 | 余额管理、资金流水、结算 | Account |
| 风控上下文 | 交易检测、规则引擎、黑白名单 | RiskAssessment |
2.5 战术设计总结
在支付订单系统的建模过程中,DDD 的战术构件提供了清晰的职责划分:
- 实体负责有身份的状态管理,如订单状态机流转。
- 值对象封装无身份的业务量,如金额、费率、地址。
- 聚合保证数据一致性边界,聚合根是唯一入口。
- 领域事件实现跨聚合的最终一致性通知。
- 限界上下文划定模型边界,避免概念污染。
下一阶段提示:掌握这些基础后,我们将进入支付订单系统的具体聚合建模,识别哪些实体应该放在同一个聚合内,哪些应该拆分到不同的限界上下文中。