规范模式(Specification)
用途:业务判定条件重复出现、需要组合与解释“为什么不通过”时查阅
定义
「定义」小节链接规范是把“某个对象是否满足某条业务规则”封装成一等对象:isSatisfiedBy(candidate): boolean,并支持组合(与、或、非)。
它回答的是“是否满足条件”,而不是“怎么改状态”,因此与聚合根上的命令方法互补。
由来与要解决的问题
「由来与要解决的问题」小节链接同一条判定(如“该客户是否符合升级条件”)往往在多个入口重复出现:页面提示、提交校验、定时批处理、报表筛选。散落的 if 条件会随规则演进而互相矛盾。规范把规则集中表达一次,并可命名(业务方能读懂的命名)。
Eric Evans 与 Martin Fowler 在《企业应用架构模式》中均给出该模式。
典型结构
「典型结构」小节链接Specification ├─ isSatisfiedBy(obj) 内存判定 ├─ and / or / not 组合 └─ toCriteria() 可选:翻译为 SQL/查询条件(用于批量筛选)双轨实现(内存判定 + 查询翻译)是常见需求:单个对象校验与批量筛选共用同一份规则定义,避免两套逻辑漂移。
适用场景
「适用场景」小节链接| 场景 | 例子 |
|---|---|
| 规则需要向用户解释 | “不满足条件的原因”(配合可返回理由的变体) |
| 规则可组合、频繁调整 | 折扣叠加、准入门槛、风控规则链 |
| 同一规则多处复用 | 提交校验 + 列表筛选 + 定时任务 |
| 需要单元测试覆盖规则本身 | 每条规则独立测试,不必起完整用例 |
常见误区
「常见误区」小节链接| 误区 | 修正 |
|---|---|
| 规范里修改对象状态 | 规范只判定,不产生副作用 |
| 为一次性简单判断建规范 | 直接写在聚合里,避免抽象泛滥 |
| 规则组合后无法解释失败原因 | 返回带原因的结果类型,或提供 explain() |
| 查询翻译与内存判定不一致 | 用同一份 DSL 生成两者,或用测试对齐 |
与其他概念的关系
「与其他概念的关系」小节链接- 聚合根:不变式由聚合守护,规范可用于表达其中可复用的判定部分。
- 领域服务:跨对象判定可由领域服务调用若干规范完成。
- 状态机:迁移的守卫条件适合表达为规范。
延伸阅读
「延伸阅读」小节链接- Eric Evans《领域驱动设计》第 9 章(Specification)
- Martin Fowler《企业应用架构模式》(Specification 章节)
- Vaughn Vernon《实现领域驱动设计》(规范与组合示例)