跳转到内容

规范模式(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《实现领域驱动设计》(规范与组合示例)