最近有个系统从0开始建设,是实践领域模型非常好的机会。于是基于多年的领域模型的理论研究和思考+AI辅助的模式,完成从建模设计、架构搭建、基础代码生成、核心模块开发、到上线运营一整套流程!
当使用领域模型完成这一套系统开发后,又有了许多新发现和思考。
一、系统建模的本质
任何系统设计最终都可以抽象为一个 schema 表达结构。无论画的是流程图、架构图还是数据模型,其核心思路都是识别系统中的“层级”和“关系”。
因此,任何系统理论上都可以用树型结构来表达。树是一种二维结构,但现实系统通常是多维的。
系统会像树一样成长,会随着业务的变化而变化,于是就引出一个关键问题:哪些维度是变化的,哪些是相对稳定的?
二、变化的维度:场景与流程
1. 场景(Context)变化
在领域建模中,场景称为 Context(上下文),Spring 中的 ApplicationContext
也体现了相似的设计理念。
Context 的核心目的是将边界清晰地划分。例如:
- 购物车 Context:仅计算商品、优惠券、换购等优惠
- 结算页 Context:除了商品优惠,还涉及个人权益、优惠方案选择、口令处理等
两者都可以使用同一个 OrderContext 进行核心优惠逻辑的复用,但上下文的差异,决定了它们需要定义不同的行为边界。
用上下文表示这些差异,比使用文档描述更清晰、准确 —— 最好的文档就是代码本身。
不过需要注意:Context 设计也要克制,过度拆分会导致熵增。因此,应给上下文制定合适的层级和命名规范,保持清晰性。
2. 流程变化
流程是系统中变化最大的一部分,具体变化包括:
- 顺序变化
- 条件变化
- 参数变化
- 结构变化
- 路径与依赖关系变化
面向流程编程虽然上手容易,但流程一旦变得复杂、嵌套、条件多,就变得非常难以维护。
举例说明:
需求:“人吃饭”
面向流程的实现:你要关心米从哪来、怎么洗、饭熟没、谁煮的……
面向对象的实现:你只需要操作一个“饭”对象,它知道自己是熟的,你只需要调用eat(fan)
。
这种设计思维上的转变,本质就是充血模型的落地方式。
三、定义的不确定性与变化的必然性
系统中很多“定义”在不同阶段会发生变化,这是系统演进中最具挑战性的部分。
示例:一品多供
- 旧定义:一个商品由多个供应商供应,价格和规格是固定的
- 新定义:一品多供只是一个组 ID,每个供应商有独立的价格和属性
语言的不确定性、业务概念的模糊性,都会直接影响代码结构。这是我们为何需要依赖领域模型来抽象不变核心的原因。
四、不易变化的维度:领域模型与层级结构
- 领域模型本身的定义通常不变。虽然随着业务发展,模型会细化(如字段变为对象、属性拆出系统),但模型的语义(如“活动”、“时间”)通常保持稳定。
- 领域模型的层级结构相对稳定,一旦定义清楚,其子类、结构关系就不易发生变化。例如:定义“营销工具”后,券、满减、余额、换购等子类就确定了,不再轻易变动。
- 代码结构层级不易变,如架构图、模块层级、模板与实例的关系等。
五、为什么需要领域模型
当你建立好领域模型后,只要场景资源准备齐全,业务场景的组合就非常灵活。
类比说明:
你有一支施工队(领域对象),他们可以建房也可以修路:
- 建房场景需要房子用料、图纸、资源 → 场景上下文
- 修路场景需要沥青、工具、路线规划 → 场景上下文
领域模型提供了稳定的“能力”,场景只是提供资源、建立关系并组织行为。
这就是领域建模的精髓:找出共性,将变化隔离到边界中。
六、建模通用步骤:一切皆对象
任何业务流程可以抽象为以下五步,适用于所有业务系统设计:
- 创建领域对象
- 创建业务场景(Context)
- 在场景中建立对象关系
- 在关系中进行计算
- 在场景中组装最终结果
七、关系管理与关系有效性
- 关系是否成立由参与的对象自身决定(如有效性验证)
- 所有关系都可以建模为 1:1
- 若为 1:N,则代表系统可能需要进行领域拆分,如“商品与导购”、“营销工具与优惠券”
八、充血模型:思维的转变
思考角度 | 传统贫血模型(事务脚本) | 充血模型(领域模型) |
---|---|---|
模型视角 | Entity 是数据容器(DTO) | Entity 拥有行为和逻辑 |
业务行为 | 写在 Service 里 | 写在 Entity 或 Domain Object 中 |
代码职责 | Service 肥大,Entity 无脑 | Entity 充实,Service 变薄 |
封装性 | 数据行为分离,易出错 | 数据与行为绑定,增强一致性 |
编程方式 | 谁来调用?怎么调用? | 对象该做什么?它职责是什么? |
可维护性 | 易失控,缺乏内聚 | 高内聚,变更局部化 |
建模方式 | 结构导向(建表 → CRUD) | 语义导向(动词行为 → 对象) |
九、做“减法”的系统设计哲学
- 避免继承 → 简化泛型
- 避免使用 Map 表示对象 → 使用明确结构
- 避免 Redis 数据结构绑死逻辑 → Redis 只是缓存
- 使用轻量级 ORM(JPA)
- 避免 Lua 脚本、避免分布式锁/事务
- Service 只负责流程调度,不承载领域逻辑
- 上下文对象(Context)是充血的,拥有自洽能力
十、系统成长与组织模型
- 系统的成长 = 领域模型的扩展 + 新领域模型的引入
- 成熟系统从“数据表驱动”转为“对象关系驱动”
- Redis、高性能缓存、事件系统都是“后技术”阶段的事,前期不必强行引入
- 系统模块按领域划分,而非按技术层或流程拆分
- 领域建模的核心是将管理学思想转化为工程模型
✨ 总结
领域模型不仅是代码结构,更是一种面向对象建模的哲学。只有业务足够理解,建模才有效 —— 否则很容易建错、推翻、返工。
但一旦建模成功,系统便获得了“可演化”的基础。后续扩展、维护、重构都能沿着已有的边界自然生长。
原创作者: wxwall 转载于: https://www.cnblogs.com/wxwall/p/18969899建模的目标,不是把系统做复杂,而是让系统在复杂面前依然清晰、稳定、可成长。