在很多后端项目中,我们经常看到这样的现象:
-
业务规则写在 Controller
-
状态判断散落在各个 Service
-
金额计算到处复制
-
一个需求改动,十几个类跟着改
这类系统的共同问题只有一个:
没有领域建模。
领域建模不是画 UML 图,也不是搞学术概念,
它的本质是:
把"混乱业务"变成"有规则、有结构、有边界"的系统内核。
一、什么是领域建模?
一句话定义:
从业务需求中提炼对象、规则与边界,让业务有归属地。
领域建模不是为了"优雅",
而是为了:
- 降低复杂度
- 防止规则散落
- 提高可维护性
- 为未来拆服务做准备
二、领域建模在系统中的位置
典型结构:
Controller
↓
Biz(流程编排)
↓
Domain(领域建模发生的地方)
↓
Repository
Domain 层不是一个"包",
而是整个业务的 规则核心区。
三、领域建模建什么?
领域建模不是随便建类,而是围绕 6 个核心概念展开。
1. Entity(实体)
有身份、有生命周期的对象。
特征:
- 有唯一 ID
- 有状态变化
- 生命周期长
- 可以被追踪
例子:
- User
- Order
- Product
注意:
不是所有数据库表都是实体。
2. Value Object(值对象)
没有身份,只代表"值"。
特征:
- 不可变
- 只比较内容
- 可复用
- 生命周期短
例子:
- Money
- Address
口诀:
实体比 ID,值对象比内容。
3. Aggregate(聚合)
一组相关实体的集合。
作用:
- 保证内部一致性
- 限制外部访问入口
示例:
Order
├─ OrderItem
└─ PaymentInfo
原则:
外部只能操作"聚合根"。
4. Domain Service(领域服务)
当规则不属于单一实体时出现。
例如:
- 价格计算
- 优惠策略
- 风控判断
特征:
- 无状态
- 不依赖技术组件
- 只依赖领域对象
5. Bounded Context(边界上下文)
领域建模中最容易被忽略,却最重要的点。
含义:
每个业务领域都有自己的词汇体系。
例子:
| 在订单系统 | 在物流系统 |
|---|---|
| 状态=已发货 | 状态=待揽件 |
词一样,含义不同。
Bounded Context 的作用:
- 防止概念污染
- 防止跨域误解
- 控制复杂度
6. Ubiquitous Language(统一语言)
团队内部的业务词典。
原则:
- 代码名词 = 产品名词
- 不出现技术名词污染业务
错误例子:
java
processData()
handleInfo()
正确例子:
java
createOrder()
cancelOrder()
四、状态机思维(很多人漏掉的关键)
实体往往有状态流转:
java
创建 → 支付 → 发货 → 完成 → 退款
如果没有状态机:
- 状态混乱
- BUG 爆炸
- 规则分散
状态机让规则集中在 Domain,而不是散落在各处。
五、规则归属(最实用的一点)
领域建模的核心问题:
这条规则属于谁?
例子:
| 规则 | 归属 |
|---|---|
| 金额计算 | Order |
| 库存扣减 | Inventory |
| 优惠策略 | Promotion |
规则放错位置,
系统复杂度会指数级上升。
六、Repository 的领域意义
Repository 不是 DAO,
它的本质是:
领域对象的持久化接口。
作用:
- 隔离数据库
- 保护领域模型纯净
- 防止 SQL 污染业务规则
口诀:
Domain 不碰数据库。
七、领域建模真正培养的能力
不是会画类图,
而是四种能力:
-
抽象能力 ------ 从需求中提炼对象
-
边界能力 ------ 控制概念范围
-
归属能力 ------ 规则放对位置
-
语言能力 ------ 名词动词统一
八、总结口诀(认知篇记忆版)
可以记住这六句:
找实体
抽值对象
划聚合
明边界
统一语言
控状态
领域建模的终极目标不是"优雅",
而是:
让业务有结构,让规则有归属,让系统可演进。