领域建模战术:解密规格模式(Specification)在复杂业务校验中的设计
在面向复杂业务场景的软件开发中,我们经常需要对领域对象(如“贷款申请”)执行极其繁琐且不断变化的规则校验(如“申请人年龄必须在 18-60 岁之间”、“账户近 6 个月不能有逾期记录”、“综合信用评分必须大于 70 分”)。
如果将这些校验逻辑直接写在聚合根或实体(Entity)的内部,会导致聚合根的方法异常臃肿,且这些校验规则极难在其他场景(如数据库检索筛选、数据报表分析)中复用。如果写在应用服务层,又会导致领域逻辑的外泄与贫血。
为了解决这种**业务校验规则的解耦、复用与自由组合**问题,领域驱动设计(DDD)提出了专门的战术模式——**规格模式(Specification Pattern)**。
本文将系统拆解规格模式的战术职责、逻辑组合拓扑设计、以及基于 Java 的规约对象实现。
一、 规格模式(Specification)的核心战术定位
规格模式是一种**特殊的领域组件**,它将单个业务规则封装进一个独立的、只读的规约对象中:
| 特征维度 | 常规内联校验 (Inline Validation) | 规格模式校验 (Specification) |
|---|---|---|
| 代码放置位置 | 直接硬编码在聚合根(如 User)的业务方法中。 | **封装在独立的规格类(如 UserActiveSpec)中**。 |
| 业务规则组合 | 通过繁琐的 if-else 与 && / || 进行嵌套拼接。 | **支持链式调用与组合**。如 specA.and(specB).or(specC)。 |
| 逻辑职责复用 | 仅能用于当前内存对象的验证。 | **三合一复用**:对象验证、数据库按规格检索(SQL 拼接)、按规格生成新对象。 |
二、 规格组合的逻辑流转拓扑
规格模式通过组合模式(Composite Pattern)能够像搭积木一样,动态拼接出任意复杂的判定网格:
[ 待校验对象: LoanApplication (贷款申请) ]
│
├─ 1. 提交给 [ 组合规格: CompositeSpecification ]
│
▼
┌─────────────┴─────────────┐
▼ (and 组合) ▼ (or 组合)
[ 规格 A: AgeRangeSpec ] [ 规格 B: CreditScoreSpec ]
- 判定年龄是否合规 - 判定信用评分是否达标
│ │
▼ (返回 boolean) ▼ (返回 boolean)
【 最终判定通过:进入下一步 】 ──<─── 汇总返回 true / false
---三、 代码实战:贷款审批场景下的规格器组合装配
以下展示了如何在 Java 中实现通用的规格基类,并构建“高风险客户贷款审批”的规格逻辑判定:
1. 领域层:通用规格接口与组合规格抽象类(Domain Layer)
package com.company.domain.spec;
/**
* 规约接口
*/
public interface Specification<T> {
boolean isSatisfiedBy(T candidate);
Specification<T> and(Specification<T> other);
Specification<T> or(Specification<T> other);
}
/**
* 组合规约抽象基类
*/
public abstract class AbstractSpecification<T> implements Specification<T> {
@Override
public Specification<T> and(Specification<T> other) {
return new AndSpecification<>(this, other);
}
@Override
public Specification<T> or(Specification<T> other) {
return new OrSpecification<>(this, other);
}
}
2. 领域层:与(AND)和或(OR)逻辑规格实现(Domain Layer)
package com.company.domain.spec;
class AndSpecification<T> extends AbstractSpecification<T> {
private final Specification<T> spec1;
private final Specification<T> spec2;
public AndSpecification(Specification<T> s1, Specification<T> s2) {
this.spec1 = s1;
this.spec2 = s2;
}
@Override
public boolean isSatisfiedBy(T candidate) {
return spec1.isSatisfiedBy(candidate) && spec2.isSatisfiedBy(candidate);
}
}
class OrSpecification<T> extends AbstractSpecification<T> {
private final Specification<T> spec1;
private final Specification<T> spec2;
public OrSpecification(Specification<T> s1, Specification<T> s2) {
this.spec1 = s1;
this.spec2 = s2;
}
@Override
public boolean isSatisfiedBy(T candidate) {
return spec1.isSatisfiedBy(candidate) || spec2.isSatisfiedBy(candidate);
}
}
3. 领域层:具体业务规格与应用(Domain Layer)
package com.company.domain.spec;
/**
* 年龄规格判定
*/
public class AgeRangeSpecification extends AbstractSpecification<User> {
@Override
public boolean isSatisfiedBy(User user) {
return user.getAge() >= 18 && user.getAge() <= 60;
}
}
/**
* 业务装配演示
*/
public class LoanApprovalDomainService {
public boolean verifyUser(User user) {
Specification<User> ageSpec = new AgeRangeSpecification();
Specification<User> creditSpec = new CreditScoreSpecification(); // 假设已定义的信用规格
// 链式拼装核心业务规则
Specification<User> loanEligibleSpec = ageSpec.and(creditSpec);
return loanEligibleSpec.isSatisfiedBy(user);
}
}
---四、 总结
规格模式(Specification Pattern)是保障核心领域知识集中、拒绝代码退化臃肿的“战术瑞士军刀”。
它通过**基于组合模式的规约封装,将零散复杂的业务校验剥离为可插拔、可组合的逻辑节点,完美捍卫了微服务内部业务逻辑的表达力**;并**以三合一的通用复用特性,达成了内存判定与数据库物理检索的逻辑底色高度统一**。掌握这套规格模式与链式组合构建技术,是应对多维复杂业务流控、重构脏乱校验代码的核心看家本领!
本站所有文章、数据、图片均来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。



暂无评论
还没有人评论过本文,快来发表你的高见吧!