策略模式的介绍

在开发中也经常遇到这种情况,实现某一个功能往往有许多算法或者策略,我们在实际开发中选择不同的算法或策略来完成该功能。一般的情况是我们会把所有的算法或策略写入一个类中,通过if...else...或case语句来根据实际情况来选择具体算法或策略,但是这种方法会使这个类臃肿,维护难,当增加一种算法或策略时又要修改源代码,违反了面向对象的单一原则和开闭原则。如果将这些算法或者策略抽象出来,提供一个统一的接口,不同的算法或策略有不同的实现类,在实际使用时通过动态注入来实现算法或策略的替换,这种模式扩展性高,维护性好,也就是本次所说的策略模式。

策略模式的定义

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们相互可以替换。让算法独立于客户端变化。

策略模式的使用场景

(1)需要安全的封装多种同一类型的操作时

(2)出现同一抽象类有多个子类,而又需要使用if..else..或case语句来选择具体子类时

策略模式的类图

策略模式-LMLPHP

 

角色介绍:

  • Context - 用来操作策略的上下文环境
  • Stragety - 策略的抽象
  • ConcreteStragetyA、B - 具体的策略实现

策略模式的简单实现

我们在写代码时经常会遇到对一个数组排序,排序的算法有很多比如插入排序,归并排序,冒泡排序等,我们在实际开发中要选择一种算法来对数组排序,一般情况下我们会这样写

public class Client {

    private static final int INSERT_SORT = 0;//插入排序
    private static final int MERGE_SORT = 1;//归并排序
    private static final int BUBBLE_SORT = 2;//冒泡排序

    public static void main(String[] args){
        Client client = new Client();
        int[] a = new int[]{1, 2, 3, 4, 5, 6};
        client.show(a,INSERT_SORT);
    }

    //显示结果
    private void show(int[] a, int type){
        if(type == INSERT_SORT){
            insetSort(a);
        }else if (type == MERGE_SORT){
            mergeSort(a);
        }else if (type == BUBBLE_SORT){
            bubbleSort(a);
        }
        for(int b : a){
            System.out.print(b + " ");
        }
    }

    //插入排序算法
    private void insetSort(int[] a){
        //TODO...
    }

    //归并排序算法
    private void mergeSort(int[] a){
        //TODO...
    }

    //冒泡排序算法
    private void bubbleSort(int[] a){
        //TODO...
    }
}

这里并不是讨论算法,就没有给出算法的具体实现,上面我们使用type类型通过if...else...语句来动态决定使用哪一种排序算法,当我们增加一种算法时,就要在函数中增加一个判断,以此类推,这样会使代码变得臃肿,一改很多处都要改。下面用策略模式进行重构,首先定义一个抽象的排序接口

抽象的排序接口,即抽象策略角色

public interface Sort{
     <T> void sort(T[] a);
}

具体策略实现类

public class BubbleSort implements Sort {
    @Override
    public <T> void sort(T[] a) {
        //这里实现冒泡排序
    }
}
public class InsertSort implements Sort{

    @Override
    public <T> void sort(T[] a) {
        //这里实现插入排序
    }
}

 

public class MergeSort implements Sort {

    @Override
    public <T> void sort(T[] a) {
        //这里实现归并排序
    }
}

客户端,用来操作策略的上下文环境,即Context角色

public class Client {

    private  Sort mSort;

    public static void main(String[] args){
        Client client = new Client();
        //设置策略
        Sort bubbleSort = new BubbleSort();
        client.setmSort(bubbleSort);
        Integer[] a = {1, 2, 3, 4, 5, 6};
        client.show(a);
    }

    public void setmSort(Sort mSort) {
        this.mSort = mSort;
    }

    public void show(Integer[] a){
        mSort.sort(a);
        for(Integer b : a){
            System.out.print(b + " ");
        }
    }

}

通过上述实例可以清晰的看出两者的区别,前面说通过if..else语句来解决问题,而后者是通过建立抽象,将不同的算法构建成一个个具体的策略实现,通过不同的策略注入实现算法替换。

总结

策略模式主要用来分离算法,在简化逻辑结构的同时,增强了系统的可读性,稳定性,可扩展性,这对于复杂的业务逻辑显得更为直观,

通过建立抽象,注入不同实现,从而达到很好的扩展性。

优点:

(1)结构清晰,使用直观

(2)耦合相对低,扩展方便

(3)操作封装更为彻底

缺点:

随着策略的增加,子类会变得很多

10-06 11:58