(设计模式)策略模式-java

来源:互联网 发布:cfd流体分析软件 编辑:程序博客网 时间:2024/06/05 05:08

•策略模式,将一个一组作用类似的算法包装起来,使他们可相互替代,算法可独立于客户端变化,且增加新的算法非常容易,也称为政策模式。
•策略模式着重于算法的替代性,即根据不同的场景使用不同的算法,系统的健壮性因此提高。
•策略模式是以算法为单位,有时候容易和模板模式混在一起,模板模式一般是一个算法中的某一步不同,算法的骨架是大致固定的,而策略模式一般是算法为一个单位。且策略模式的算法都是公共的,可独立于客户端调用,而模板模式一般不能独立调用。
•策略模式的角色组成:
①上下文角色(Context):可注入一个策略对象,持有一个策略的引用。客户端通过上下文对象来调用策略。

/** * 策略的上下文:和策略打交道,可以理解为是对策略的调用, * 上下文和接口进行复杂交互。商城的调用者和上下文打交道。 * 就比如电脑维修工,客户电脑坏了,不会去店里直接找某个维修工, * 客户只会在网上查找相关的服务或者找客服姐姐,网站或客服姐姐帮你安排相应的维修工, * 这个网站或者客服姐姐就是这个上下文,和相关的维修工打交道。 * @author btp * */public class ContextUseStrategy {    /*     * 封装了一个策略     */    private FictitiousStrategy aStrategy;    /*     * 构造一个上下文对象,将策略对象传入     */    public ContextUseStrategy(FictitiousStrategy aStrategy){        this.aStrategy = aStrategy;    }    /*     * 调用策略     */    public void executeStrategy(){        this.aStrategy.executeStrategy();    }    public FictitiousStrategy getaStrategy() {        return aStrategy;    }    public void setaStrategy(FictitiousStrategy aStrategy) {        this.aStrategy = aStrategy;    }}

②抽象策略角色(Strategy):定义了一个上下文对象可调用的公共方法。

/** * 虚拟的策略:策略的父类,表明提供策略。针对一组策略。 * 准备一组算法,并将每一个算法封装起来,使得它们可以互换。 * 策略模式代表一个算法族,算法之间可以相互替代,比如: * 我们有几个电脑维修工,维修来自客户的坏电脑,每个维修工相当于一个算法, * 根据电脑的类型和电脑的损坏程序安排维修工去维修,可能有些维修工擅长维修笔记本, * 有些擅长维修台式机,或者来了一个电脑,你搞不定我再来搞定,总有一个人能搞定 * @author btp * */public abstract class FictitiousStrategy {    /*     * 执行策略     */    public abstract void executeStrategy();}

③具体策略角色(Concrete Strategy):实现抽象策略类的公共方法,并提供不同的可替代的实现。

/** * 具体的策略类:包含真正可以执行的算法 * 从虚拟策略类继承而来。 * 比如擅长修理笔记本的维修工A * @author btp * */public class ConcreteStrategy1 extends FictitiousStrategy{    @Override    public void executeStrategy() {        //算法的实现        System.out.println("算法1执行");    }}
/** * 具体的策略类:包含真正可以执行的算法 * 从虚拟策略类继承而来 * 比如擅长维修台式机的维修工B * @author btp * */public class ConcreteStrategy2 extends FictitiousStrategy{    @Override    public void executeStrategy() {        //算法的实现        System.out.println("算法2执行");    }}

然后上层调用者就可以调用上下文环境:

/** * 上层调用者,和上下文交互 * @author btp * */public class ContextUser {    public static void main(String[] args) {        //使用算法1        ContextUseStrategy context = new ContextUseStrategy(new ConcreteStrategy1());        context.executeStrategy();        //使用算法2        context.setaStrategy(new ConcreteStrategy2());        context.executeStrategy();        //使用算法3        context.setaStrategy(new FictitiousStrategy(){            @Override            public void executeStrategy() {                //算法的实现                System.out.println("算法3执行");            }        });        context.executeStrategy();    }}

看上去就像Spring中的各种注入方式,根据不同的情况选择不同的注入方式。

•大家都知道有许多种排序方式,比如内部排序中的冒泡,插入,归并等,这些排序方式有时候也各有优缺点,比如基本有序的序列选择插入排序,数据规模较大的时候使用归并排序可能更好一点。以下就用排序算法做一个例子。

import java.lang.reflect.Array;import java.util.Arrays;//一个排序算法族public class StrategyTest {    public static void main(String[] args) {        //客户端        //使用冒泡排序        SortUse<Integer> user = new SortUse<Integer>(new Integer[]{99,2,100,33,2,2,3,555,6,7,88},new BubbleSort<Integer>());        System.out.println("冒泡排序前:"+user);        user.sort();        System.out.println("冒泡排序后:"+user);        //使用插入排序        user.setT(new Integer[]{45,2,4,111,98,54,0,1,2});        user.setSort(new InsertSort<Integer>());        System.out.println("插入排序前:"+user);        user.sort();        System.out.println("插入排序后:"+user);        //使用直接选择排序        user.setT(new Integer[]{45,2,4,111,98,54,0,1,2});        user.setSort(new SelectionSort<Integer>());        System.out.println("直接选择排序前:"+user);        user.sort();        System.out.println("直接选择排序后:"+user);        //使用归并排序        user.setT(new Integer[]{45,2,4,111,98,54,0,1,2});        user.setSort(new MergeSort<Integer>());        System.out.println("归并排序前:"+user);        user.sort();        System.out.println("归并排序后:"+user);        //使用归并排序        user.setT(new Integer[]{111,98,54,45,4,2,2,1,0});        user.setSort(new QuickSort<Integer>());        System.out.println("快速排序前:"+user);        user.sort();        System.out.println("快速排序后:"+user);    }}/* * 排序算法的上下文:持有一个排序算法的引用。和算法交互。调用排序算法。 */class SortUse<T extends Comparable<? super T>>{    private Sort<T> sort;    private T[] t;    //传入要排序的对象数组以及要使用的排序算法对象    public SortUse(T[] t,Sort<T> sort){        this.sort = sort;        this.t = t;    }    public void sort(){        this.sort.sort(t);    }    public Sort<T> getSort() {        return sort;    }    public void setSort(Sort<T> sort) {        this.sort = sort;    }    public T[] getT() {        return t;    }    public void setT(T[] t) {        this.t = t;    }    public String toString(){        return Arrays.toString(t);    }}/* *排序的虚拟类:代表一个排序算法对象。 为上下文对象定义了公共接口。 */abstract class Sort<T extends Comparable<? super T>>{    public abstract void sort(T[] t);}/* * 具体的算法实现类:实现了虚拟类的接口 * 具体的算法实现类:冒泡排序 */class BubbleSort<T extends Comparable<? super T>> extends Sort<T>{    @Override    public void sort(T[] t) {        T temp;        for(int i = t.length-1;i>=0;i--){            for(int j = i-1;j>=0;j--){                if(t[i].compareTo(t[j]) < 0){                    temp = t[i];                    t[i] = t[j];                    t[j] = temp;                }            }        }    }}/* * 具体的算法实现类:插入排序 * 将值插入一个已经排好序的序列 */class InsertSort<T extends Comparable<? super T>> extends Sort<T>{    @Override    public void sort(T[] t) {        T temp;        //从第一个开始排        for(int i = 1;i < t.length;i++){            for(int j = 0;j < i;j++){                if(t[i].compareTo(t[j]) < 0){                    temp = t[i];                    //要插入的位置之后的元素全部向后移                    for(int k = i;k > j;k--){                        t[k] = t[k-1];                    }                    t[j] = temp;                    break;                }            }        }    }}/* * 具体的算法实现类:直接选择排序 * 从后面的序列中选取最大或最小的值,将其和已经排好序的序列的后一位交换值 */class SelectionSort<T extends Comparable<? super T>> extends Sort<T>{    @Override    public void sort(T[] t) {        //记录要交换元素的坐标        int index;        //记录最小值        T min;        //临时值,交换两个坐标的值使用        T temp;        for(int i = 0;i < t.length-1;i++){            min = t[i];            index = i;            for(int j = i+1;j < t.length;j++){                if(min.compareTo(t[j]) > 0){                    min = t[j];                    index = j;                }            }            temp = t[i];            t[i] = t[index];            t[index] = temp;        }    }}/* * 具体的算法实现类:归并排序 * (1)两个序列各自排好序 * (2)合并两个排好序的序列,使之成为一个有序的序列 */class MergeSort<T extends Comparable<? super T>> extends Sort<T>{    @Override    public void sort(T[] t) {        sort(t,0,t.length-1);    }    private void sort(T[] t,int low,int high){        int middle = (low + high) / 2;        if(low < high){            //middle左边排序            sort(t,low,middle);            //middle右边排序            sort(t,middle+1,high);            //排好序的两个序列合并            mergeTwoList(t,low,middle,high);        }    }     //两个排好序的数组进行合并    @SuppressWarnings("unchecked")    private void mergeTwoList(T[] t,int low,int middle,int high){        if(t.length > 0 && null != t[0]){            //构建一个临时数组,存放排序后的值            T[] temp = (T[]) Array.newInstance(t[0].getClass(), high - low +1);            int headOfList1 = low;            int headOfList2 = middle + 1;            int indexOfTemp = 0;            while(headOfList1 <= middle && headOfList2 <= high){                if(t[headOfList1].compareTo(t[headOfList2]) < 0){                    temp[indexOfTemp++] = t[headOfList1++];                }else{                    temp[indexOfTemp++] = t[headOfList2++];                }            }            //此时一定有一个数组走空或两个数组走空,把另一个数组的残余数据移到临时数据中            while(headOfList1 <= middle){                temp[indexOfTemp++] = t[headOfList1++];            }            while(headOfList2 <= high){                temp[indexOfTemp++] = t[headOfList2++];            }            indexOfTemp = 0;            //把排好序的临时数组的数据移到原先的数组中            for(int i = low;i <= high;i++){                t[i] = temp[indexOfTemp++];            }        }else{            throw new RuntimeException();        }    }}/* * 具体的算法实现类:快速排序 *(1)在数据集之中,选择一个元素作为"基准"(pivot)。 *(2)所有小于"基准"的元素,都移到"基准"的左边;所有大于"基准"的元素,都移到"基准"的右边。 *(3)对"基准"左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。 */class QuickSort<T extends Comparable<? super T>> extends Sort<T>{    @Override    public void sort(T[] t) {        sort(t,0,t.length-1);    }    private void sort(T[] t,int low,int high){        //low < high的情况下才排序        if(low < high){            T baseObject = t[low];            int left = low;            int right = high;            //记录下一个要填的坐标值            int index = low;            while(left != right){                //防止空指针把left < right放到前面来                while(left < right && t[right].compareTo(baseObject) >= 0){                    right--;                }                t[index] = t[right];                t[right] = null;                index = right;                while(left < right && t[left].compareTo(baseObject) <= 0){                    left++;                }                t[index] = t[left];                t[left] = null;                index = left;            }            t[index] = baseObject;            //左半区排序            sort(t,low,index-1);            //右半区排序            sort(t,index+1,high);        }    }}