DDD 宏观与微观概念:限界上下文直觉
战略设计 · 第 4/15 篇
上一篇:《架构基础:SOLID、OOA/OOD 与隐式业务显式化》
下一篇:《微服务拆分原则:领域驱动而非数据驱动》
开头:从宏观边界到微观对象
DDD 既讲 战略设计(划边界、定上下文),也讲 战术设计(实体、聚合、领域服务等)。本篇建立 限界上下文 的直觉,并梳理微观层面的核心概念,最后用电商下单 demo 串起来。
一、DDD 与微服务、中台的关系
宏观上,组织可能经历「去中台」等架构调整;微观上,每个软件平台仍需清晰边界。DDD 核心概念与 建模、微服务架构设计 紧密相关——建模结果往往直接指导服务拆分与协作方式。

二、宏观概念
1. 领域与子域
领域:所要面向的客户与要开发的软件的业务范围与业务逻辑。
领域很大,只能关注某一方面并做软件建模,该模型即 领域模型。领域可按业务逻辑拆成 相互分离的子域——子域之间通过接口关联、隐藏内部细节(类似面向接口编程)。
2. 限界上下文(Bounded Context)
限界上下文可理解为:
- 常见情况:一个子域对应一个限界上下文——拆子域即拆上下文。
- 术语边界:在上下文内,术语、流程、代号有固定含义;在别的上下文可能完全不同——故需「限界」。
- 粒度:一个子域也可能含多个上下文,理论上应拆细至 一子域一上下文。
- 统一语言载体:可粗视为子域关联的一系列术语、流程与代号——确定 通用语言 的上下文。
- 与核心域关系:关注某子域时它为 核心域;支撑域、通用子域为支持核心域而存在,核心域的上下文可能包含支撑/通用子域的部分或全部。
例子:
- 「质量」在 软件限界上下文 指经过各类测试的软件;在 建筑工程 上下文则是另一含义。
- 「顾客」在 订单子域 是下单付费的登录用户;在 商品目录子域 包括匿名与登录的浏览用户——同一词不同义,不应规划到同一限界上下文。
限界上下文内通常包含:实体、值对象、聚合、领域事件、领域服务 等。它是 显式边界,领域模型存在于边界之内——可看作一种 namespace,也常对应一个系统、应用或业务服务。

3. 核心域、支撑域、通用子域
| 类型 | 含义 | 电商示例 |
|---|---|---|
| 核心域 | 当前关注的核心业务子域 | 订单子域 |
| 支撑域 | 涉及业务但非核心,为核心域提供支持 | 商品品类(提供查询支持) |
| 通用子域 | 各子域都需要,偏工具/数据/接口,不直接承载核心业务 | 账号子域 |
核心域是相对的:你当前要解决的问题对应的子域即核心域,为其提供支持的即为支撑域与通用子域。
三、微观概念
领域驱动设计围绕 领域模型,通过 分层架构 将领域独立出来。模型对象包括 实体、值对象、领域服务 等,领域逻辑应封装在这些对象中。

1. 实体(Entity)
有 唯一标识 的核心领域对象,标识在软件生命周期内不变。与数据库 Entity 类似,但 DDD 实体 包含相关业务逻辑,是操作行为的载体。
实体 = 唯一身份标识 + 可变性(状态 + 行为)
生命周期内无论怎么变,同一 ID 仍是同一实体。例如商品上下文中的商品,以商品 ID 标识,数据变化 ID 不变。

2. 值对象(Value Object)
依附实体,通过 属性集合 识别,无唯一 ID,表达领域中某类含义。用于传递参数或补充描述实体;属性只读,可安全共享。
值对象 = 用对象表述一个固定不变的概念
例如用户实体中的 地址(省市区等打包);或订单里地址 JSON 序列化存 DB 的一个字段——只关心属性时即可作为值对象。不要给值对象身份标识,避免不必要的复杂性。
| 对比 | 实体 | 值对象 |
|---|---|---|
| 标识 | 有唯一 ID | 无 ID |
| 相等性 | 比 ID | 比所有属性 |
| 生命周期 | 持续变化仍同一对象 | 属性变即新对象 |
3. 聚合(Aggregate)与聚合根
实体与值对象表达个体能力;复杂业务需多个对象 协同,协同组织即 聚合。聚合是 数据修改与持久化的基本单元,同一聚合内保证 事务一致性,设计时应 拆到足够小 以保证性能。
- 聚合属于 领域层;同一微服务领域层可有多个聚合,各有 聚合根。
- 同一限界上下文内多聚合由 应用层 组合实现核心逻辑。
- 每个聚合设计 仓储(Repository) 做持久化;尽量在一次交易中提交聚合内变更。
聚合根(Aggregate Root):聚合的入口与管理者——既是实体,又协调聚合内实体/值对象,并作为对外接口(外部通过聚合根 ID 引用,不可直接访问聚合内其他实体)。
聚合 = 聚合根 + 上下文边界(按单一职责与高内聚定义内含哪些实体/值对象;聚合间松耦合)。
建模步骤示例(如投保场景):事件风暴得到实体与值对象 → 聚合成「投保聚合」「客户聚合」,投保单/客户为聚合根 → 找出与聚合根紧密依赖的对象 → 画引用依赖模型。
4. 领域服务 vs 应用服务
领域服务(Domain Service)
- 动词类操作,涉及 多个领域对象、又不自然属于某一实体/值对象时,声明为领域服务。
- 典型场景:显著业务操作;领域对象转换;多对象输入计算产出值对象。
- 特征:代表领域概念;无状态;避免领域逻辑泄露到应用层。
- 勿滥用——理想情况无领域服务;过度使用会退回「逻辑全在 Service 层」。
应用服务(Application Service)
- 展现层与领域层的 桥梁,表达用例与用户故事;编排与转发,委托领域对象实现,自身较「薄」。
- 可处理安全、权限、事务、发消息等;不是 领域模型的一部分。
- 跨多个实体 用领域服务;跨多个聚合 用应用服务(避免聚合间领域服务直接调用,上升到应用层编排)。
5. 领域事件 / 领域命令
领域事件 表示领域中已发生的事(过去时)或状态变化,如充值成功/失败。
领域事件 = 事件发布 + 存储 + 分发 + 处理
- 触发点在领域模型;使领域对象摆脱对 Repository/Service 的直接依赖——需要时 发事件,由监听方处理(设计维度的解耦;EventBus、MQ 是实现层异步解耦)。
- 流程:构建唯一标识事件 → 发布前存储(重试/对账)→ 服务内直发订阅者,跨服务用 MQ → 存储后处理。
例如:下单成功后发布 订单创建事件,积分聚合、优惠券聚合各自监听处理——避免瀑布式长链 if-else。
6. 仓储(Repository)与工厂(Factory)
仓储:管理 聚合 集合,介于领域模型与数据模型之间,负责聚合的持久化与检索——存取单位是 聚合(要么整取要么整删),隔离持久化细节。
工厂:封装创建复杂对象(尤其聚合)的知识,隐藏创建细节;仅当创建逻辑复杂时使用。工厂管 创建,仓储管 持久化生命周期——共同管理领域对象生命周期。
四、Demo:电商下单场景
用熟悉的 电商下单 串起概念(简化):
1. 实体
- 商品:唯一标识、名称、价格、库存等。
- 订单:唯一标识、下单时间、状态等;包含多个订单项。
2. 值对象
- 地址:省、市、区、详细地址等。
3. 聚合根
- 商品聚合根:含商品实体及相关值对象,负责商品 CRUD。
- 订单聚合根:含订单实体及相关值对象,负责订单 CRUD。
4. 领域事件
| 事件 | 触发时机 | 典型数据 |
|---|---|---|
| 订单创建 | 用户下单 | 订单信息、商品信息 |
| 订单支付 | 支付完成 | 订单信息、支付金额 |
| 订单发货 | 商家发货 | 订单信息、快递公司与单号 |
5. 应用服务
- 创建订单:接收购买请求,创建订单,发布订单创建事件。
- 支付订单:更新状态,发布支付事件。
- 发货:更新状态,发布发货事件。
- 查询订单:按订单号等条件查询。
商品与订单是两个核心领域概念,各由聚合根管理;领域事件驱动不同场景的数据更新与通知;应用服务对外提供用例入口——这是 DDD 战略边界 + 战术对象的一次 最小闭环。
小结
| 层次 | 关键概念 |
|---|---|
| 宏观 | 领域、子域、限界上下文、核心/支撑/通用子域 |
| 微观 | 实体、值对象、聚合/聚合根、领域服务、应用服务、领域事件、仓储、工厂 |
建立 限界上下文 直觉后,下一篇讨论 微服务如何按领域拆分,而非按表拆分。