本文节选自《设计模式就该这样学》

1 规格模式的定义

规格模式(Specification Pattern)可以认为是组合模式的一种扩展。很多时候程序中的某些条件决定了业务逻辑,这些条件就可以抽离出来以某种关系(与、或、非)进行组合,从而灵活地对业务逻辑进行定制。另外,在查询、过滤等应用场合中,通过预定义多个条件,然后使用这些条件的组合来处理查询或过滤,而不是使用逻辑判断语句来处理,可以简化整个实现逻辑。

这里的每个条件都是一个规格,多个规格(条件)通过串联的方式以某种逻辑关系形成一个组合式的规格。规格模式属于结构型设计模式。

2 规格模式的应用场景

规格模式主要适用于以下应用场景。

(1)验证对象,检验对象本身是否满足某些业务要求或者是否已经为实现某个业务目标做好了准备。

(2)从集合中选择符合特定业务规则的对象或对象子集。

(3)指定在创建新对象的时候必须要满足某种业务要求。

3 规格模式的UML类图

规格模式的UML类图如下图所示。

由上图可以看到,规格模式主要包含6个角色。

(1)抽象规格书(Specification):对规格书的抽象定义。

(2)组合规格书(CompositeSpecification):一般设计为抽象类,对规格书进行与或非操作,实现and()、or()、not()方法,在方法中关联子类,因为子类为固定类,所以父类可以进行关联。

(3)与规格书(AndSpecification):对规格书进行与操作,实现isSatisfiedBy()方法。

(4)或规格书(OrSpecification):对规格书进行或操作,实现isSatisfiedBy()方法。

(5)非规格书(NotSpecification):对规格书进行非操作,实现isSatisfiedBy()方法。

(6)业务规格书(BizSpecification):实现isSatisfiedBy()方法,对业务进行判断,一个类为一种判断方式,可进行扩展。

4 规格模式的通用写法

以下是规格模式的通用写法。


public class Client { public static void main(String[] args) {
//待分析的对象
List<Object> list = new ArrayList<Object>();
//定义两个业务规格书
ISpecification spec1 = new BizSpecification("a");
ISpecification spec2 = new BizSpecification("b");
//规格调用
for (Object o : list) {
if(spec1.and(spec2).isSatisfiedBy(o)){ //如果o满足spec1 && spec2
System.out.println(o);
}
}
} //抽象规格书
interface ISpecification {
//候选者是否满足条件
boolean isSatisfiedBy (Object candidate) ;
//and操作
ISpecification and (ISpecification spec);
//or操作
ISpecification or (ISpecification spec);
//not操作
ISpecification not ();
} //组合规格书
static abstract class CompositeSpecification implements ISpecification {
//是否满足条件由子类实现
public abstract boolean isSatisfiedBy (Object candidate) ;
//and操作
public ISpecification and (ISpecification spec) {
return new AndSpecification(this, spec);
}
//or操作
public ISpecification or(ISpecification spec) {
return new OrSpecification(this, spec);
}
//not操作
public ISpecification not() {
return new NotSpecification(this);
}
} //与规格书
static class AndSpecification extends CompositeSpecification {
//传递两个规格书进行and操作
private ISpecification left;
private ISpecification right; public AndSpecification(ISpecification left, ISpecification right) {
this.left = left;
this.right = right;
} //进行and运算
public boolean isSatisfiedBy(Object candidate) {
return left.isSatisfiedBy(candidate) && right.isSatisfiedBy(candidate);
}
} static class OrSpecification extends CompositeSpecification {
//传递两个规格书进行or操作
private ISpecification left;
private ISpecification right; public OrSpecification(ISpecification left, ISpecification right) {
this.left= left;
this.right = right;
} //进行or运算
public boolean isSatisfiedBy(Object candidate) {
return left.isSatisfiedBy(candidate) || right.isSatisfiedBy(candidate);
}
} static class NotSpecification extends CompositeSpecification {
//传递两个规格书进行非操作
private ISpecification spec; public NotSpecification(ISpecification spec) {
this.spec = spec;
} //进行not运算
public boolean isSatisfiedBy(Object candidate) {
return !spec.isSatisfiedBy(candidate);
}
} //业务规格书
static class BizSpecification extends CompositeSpecification {
//基准对象,如姓名等,也可以是int等类型
private String obj;
public BizSpecification(String obj) {
this.obj = obj;
}
//判断是否满足要求
public boolean isSatisfiedBy(Object candidate){
//根据基准对象判断是否符合
return true;
}
}
}

5 规格模式的优缺点

5.1 优点

规格模式非常巧妙地实现了对象筛选功能,适合在多个对象中筛选查找,或者业务规则不适于放在任何已有实体或值对象中,而且规则变化和组合会掩盖对象的基本含义的情况。

5.2 缺点

规格模式中有一个很严重的问题就是父类依赖子类,这种情景只有在非常明确不会发生变化的场景中存在,它不具备扩展性,是一种固化而不可变化的结构。一般在面向对象设计中应该尽量避免。

关注微信公众号『 Tom弹架构 』回复“设计模式”可获取完整源码。

【推荐】Tom弹架构:30个设计模式真实案例(附源码),挑战年薪60W不是梦

本文为“Tom弹架构”原创,转载请注明出处。技术在于分享,我分享我快乐!

如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。关注微信公众号『 Tom弹架构 』可获取更多技术干货!

最新文章

  1. CI Weekly #9 | 揭秘阿里 Docker 化实践之路
  2. 原生HTML5 input type=file按钮UI自定义
  3. jQuery对表格的操作及其他应用
  4. HTTP状态码大全
  5. TSuperEnumerator、TSuperAvlIterator、ObjectFindFirst
  6. mac显示所有文件、不产生.DS_Store文件
  7. configure.ac:32: error: possibly undefined macro: AC_DEFINE
  8. c++ deque 双端队列
  9. Vim键盘图与命令图解
  10. ROR入门之旅
  11. 【转】Java 枚举7常见种用法
  12. Linux UGO和ACL权限管理
  13. 使用CocoaPods出现 The `master` repo requires CocoaPods 0.32.1 - 问题解决
  14. IO流程中IO向量iovec
  15. 纯干货!华为软件开发云编译构建之Maven
  16. C语言的产生
  17. 更多more 123123循环
  18. Codeforces 986D Perfect Encoding FFT
  19. [leetcode] 20. Valid Sudoku
  20. kubernetes master 高可用一键部署

热门文章

  1. FastAPI 学习之路(九)请求体有多个参数如何处理?
  2. C 函数指针 函数指针数组 转移表
  3. gin 源码阅读(5) - 灵活的返回值处理
  4. Linux命令(二)
  5. SpringCloud微服务实战——搭建企业级开发框架(二):环境准备
  6. 【Azure 应用服务】App Service For Linux 如何在 Web 应用实例上住抓取网络日志
  7. Prometheus之告警规则的编写
  8. UVA-1498 Activation
  9. STM32必学的时钟系统
  10. 轻松掌握stm32直流电机驱动与测速