策略设计模式

时间:2021-07-09 23:31:17

一、基本定义  

         

         策略设计模式:“针对”一组算法,“将”每一个算法封装到具有相同接口的独立的类中,“从而”使它们可以相互替换。


二、目的

        策略设计模式的重点不是如何实现算法,而是如何组织、调用这些算法。策略设计模式让程序的结构更加灵活,让系统具有更好的灵活性和扩展性,降低需求变动的维护成本。


三、代码实现

        策略设计模式代码有三个主体。

        1.持有抽象策略的引用的类

        2.抽象策略类

        3.具体策略类

        范例一:策略模式经典代码

public class Context {
    private Stategy stategy;

    public Context(Stategy stategy) {
        this.stategy = stategy;
    }

    public int result(){
        return stategy.function();
    }
    //主函数可以视为要被调用的环境,例如Service中,或者是Controller中
    public static void main(String[] args) {
        Context context = new Context(new Stategy1());
        System.out.println(context.result());

    }
}
//抽象策略
interface Stategy{
    int function();
}
//具体三种策略实现
class Stategy1 implements  Stategy{

    @Override
    public int function() {
        return 1;
    }
}
class Stategy2 implements  Stategy{

    @Override
    public int function() {
        return 2;
    }
}
class Stategy3 implements  Stategy{

    @Override
    public int function() {
        return 3;
    }
}

        这个例子里面Context类持有着抽象策略的引用,由构造函数接收抽象策略实现类。Context调用的result()方法,其实就是包裹的策略的function()方法。根据具体情况,选择不同的策略的实现类,传递给Context类的构造器。


        范例二:策略模式与简单工厂模式结合

        这种方式更加适合与MVC模式。Controller代码中不直接生成相关策略,根据前台传递过来的参数,交由Context类的构造函数,在Context类的内部进行选择具体的实现类。Controller层里面的代码只需要知道Context类,根本不需要知道具体的策略类。在发生需求变动的时候,我们修改的类是Context类的构造函数,修改switch()语句,因此Controller层的代码不需要变动。代码如下:

        

public class Context {
    private Stategy stategy;
    public Context(int i) {
        switch (i){
            case 1:{
                stategy = new Stategy1();
                break;
            }
            case 2:{
                stategy = new Stategy2();
                break;
            }
            case 3: {
                stategy = new Stategy3();
                break;
            }
            default:{
                stategy = new Stategy1();
            }
        }

    }

    public int result(){
        return stategy.function();
    }

    //此主函数可以看作是要实际应用的环境,比如某个Controller中
    public static void main(String[] args) {
        Context context = new Context(3);//这个构造函数的参数由前端传递过来
        System.out.println("结果是:"+context.result());

    }
}
//策略
interface Stategy{
    int function();
}
//具体实现三种
class Stategy1 implements  Stategy{

    @Override
    public int function() {
        return 1;
    }
}
class Stategy2 implements  Stategy{

    @Override
    public int function() {
        return 2;
    }
}
class Stategy3 implements  Stategy{

    @Override
    public int function() {
        return 3;
    }
}

        上述代码可以看到,我们的主函数中(可以理解为Controller中),只有Context类的代码,没有出现具体的策略类。调用Context的result()方法,实际上就是包裹调用策略类的function()方法。这个时候,如果出现需求变动,我们Controller层的代码是不需要变动的,修改的是Context类中的switch()语句。

        有同事说策略模式的好处之一就是可以避免 if - else 语句,我是不赞成的,因为不管怎么说,策略模式是根据不同的情况选择不同的策略,那么这个过程必然会有 条件选择语句。if - else 语句也好,swicth语句也好,条件语句经过判断,选择出具体的实现类,因此它们在策略模式中是不可避免的。

四、策略模式的特点

        各个封装的算法地位平等,并且同一时刻只能使用其中的一种策略实现类。

        它们具有相同的接口,可以相互进行替换。


五、优缺点

        优点:由于策略模式的扩展性与灵活性,代码变得便于维护。在实际中,从前端接收一个参数,然后调用简单工厂的构造函数,在简单工厂内部创建这个策略的实例对象,调用简单工厂的方法返回结果即可。代码可参考第二个例子。

        缺点:策略模式因为需要将每一个策略都封装成具有相同接口的独立的类,如果当前系统中策略很多,无异于增加了代码开发的量。另外,在调用这些策略的时候,需要对每一个策略都要了解,增加了系统的复杂性。