首页 > 代码库 > 2.2策略模式(5.9)

2.2策略模式(5.9)

某种程度上,策略模式不值得一提,因为学习和理解它,其难度系数为0。不就是一个类层次的问题吗。

所以,我们添加一点内容:方法对象化——将方法封装为类型。

另外,从重构分支结构的角度看,策略模式与[1.3.2工厂方法模式(3.3)]和[3.2状态模式(5.8)]是三胞胎。

1.父类定义接口,子类给出实现

外出旅游时,可以在多种不同的出行方式中选择,如坐汽车/火车/飞机、骑自行车或步行。海关对不同的商品按照不同的税率征收关税……做事情的方式即策略或政策。在源代码中,一个方法体常常被称为一个算法,故封装做事情方式的一个方法体,被称为一个具体的策略

策略模式以类层次定义和封装算法集:父类定义接口,子类给出实现。【策略模式(Strategy Pattern):定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。

如【编程导论·11 排序】介绍了各种各样的排序算法:选择、插入和交换排序等。为了方便地测试各种算法,抽象类algorithm.sorting.IntSort封装了抽象方法int[] sort(int[] arr),各种排序算法被设计成IntSort的子类。当然,IntSort除了包括策略,还可以提供了工具方法:如public static void swap(int[] arr ,int one, int two)——交换数组的两个元素。

从封装算法集的角度看,策略模式就是设计一个类层次。因而,学习和理解它,其难度系数为0。策略模式仅仅简单地使用了多态技术。正因为策略模式仅仅简单地使用了多态技术,因而策略模式成为其他模式常用的一个基本技术。也可以说,策略模式没有技术含量。

2. 将策略从环境类中分离出来

还是以排序为例,

package method.strategy;
public class Context{
    public void test(String s,int i,int j,int[] array){
        if(s == "选择") m1(i,j);
        if(s == "插入") m2(array);
        if(s == "交换") m3(array,i);
    }

    private void m1(int i,int j){}
    private void m2(int[] array){}
    private void m3(int[] array,int i){}    
}
如果按照分支结构测试各种算法,在可能增加分支的场合该代码不遵循OCP。显然的解决方案是,设计MyStrategy的abstract方法m(int i,int j,int[] array)封装各种算法m1、m2、m3。在实际编程中,原来的m1()、m2()、m3()可能需要各种不同的参数。因此设计抽象方法m()时,在保证返回值类型确定的前提下,m()必须能够保证所有具体的策略类能够获得它需要的所有数据,因而在定义m()的接口时,它的参数列表是具体的策略类所需数据的最大集合。最大集合意味着宁可多不可少——某些具体策略类可以不使用参数列表提供的数据,但是不可使得某些具体策略类缺乏需要的数据。当然,仅就排序而言,参数情况简单。
package method.strategy;
public interface MyStrategy{
    public abstract int[] sort(int[] arr);
}// MyStrategy的子类型,略
注意,我们由于拥有依赖注入工具import tips.IoC,

package method.strategy; 
import tips.IoC;
public class Context{
    private MyStrategy s;
    //依赖注入
    public void setStrategy(MyStrategy s){
        this.s=s;
    }

    public static void test(int[] arr){
        MyStrategy st =(MyStrategy)IoC.getObject("插入");
        int[] array = st.sort(arr); 
    }   
}

3.

2.2策略模式(5.9)