规格模式(Specification Pattern)

规格模式是一种扩展的组合模式,用于将业务逻辑中的条件抽取并组合,简化复杂判断。通过抽象规格书、组合规格书、与规格书、或规格书和非规格书等角色,实现灵活的条件组合。常用于对象验证、集合筛选和创建新对象时的条件检查。其优点在于提供了一种更清晰的逻辑表达方式,但缺点是可能导致父类对子类的强依赖。
摘要由CSDN通过智能技术生成

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

1 规格模式的定义

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

2 规格模式的应用场景

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

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

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

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

3 规格模式的UML类图

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

file

由上图可以看到,规格模式主要包含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弹架构 』回复“设计模式”可获取完整源码。

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

在这里插入图片描述

本文为“Tom弹架构”原创,转载请注明出处。技术在于分享,我分享我快乐!
如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。关注微信公众号『 Tom弹架构 』可获取更多技术干货!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tom弹架构

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值