规格模式(Specification Pattern)

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

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

1 规格模式的定义

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

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

2 规格模式的应用场景

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

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

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

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

3 规格模式的UML类图

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

20211125190011452.png

由上图可以看到,规格模式主要包含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 规格模式的优点

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

6 规格模式的缺点

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

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


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

如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。

相关文章
|
9月前
|
设计模式 uml
雇工模式(Employee Pattern)
雇工模式(Employee Pattern)也叫作仆人模式(Servant Pattern),属于行为型设计模式,它为一组类提供通用的功能,而不需要类实现这些功能,也是命令模式的一种扩展。
38 0
|
9月前
|
设计模式 uml
空对象模式(Null Object Pattern)
空对象模式(Null Object Pattern)不属于GoF设计模式,但是它作为一种经常出现的模式足以被视为设计模式了。其具体定义为设计一个空对象取代NULL对象实例的检查。NULL对象不是检查控制,而是反映一个不做任何动作的关系。这样的NULL对象也可以在数据不可用的时候提供默认的行为,属于行为型设计模式。
55 0
|
11月前
|
存储 设计模式 缓存
Flyweight Pattern: 让你的代码更加轻量
你是否曾经遇到过这样的情况:你的应用程序中有大量的对象实例,而这些对象的大部分属性都是相同的?当这些相似的对象多到让你的内存感到吃不消时,Flyweight Pattern(享元模式)就是你的救星!Flyweight Pattern 可以帮助你减少内存占用,提高性能,并让你的代码更加轻量。
52 0
|
Java
Java Business Delegate Pattern(业务代表模式)
业务代表模式(Business Delegate Pattern)用于对表示层和业务层解耦。它基本上是用来减少通信或对表示层代码中的业务层代码的远程查询功能。
1185 0
|
Java
log4j中Pattern布局ConversionPattern详解
spring使用log4j,可以有2种方法。 1、在web.xml里不做任何配置。 log4j.properties放在classpath根目录下, 这时候生成的日志文件就没有相对路径,如果写相对路径,则会生成在安装tomcat的根路径下。 2、在web.xml设置。 &lt;context-param&gt;           &lt;param-name&gt;log4jConfi
1822 0