策略模式(strategy pattern)

摘要:
该策略模式在Java集合中的TreeSet和TreeMap中得到了很好的应用。我们可以实现Comparator接口和Compareto()方法来定义自己的排序规则,然后通过TreeSet和TreeMap构造方法传入实现接口的实例。地图上的订单将是我们的定制订单。当我们想到数据结构中的各种排序时,如气泡排序、快速排序和堆排序,它们都有相同的功能,但它们的排序算法不同。首先,定义我们的抽象策略:/***抽象策略类*@author**/publicinterfaceStrategy{publicvoid sort;}ViewCode定义了特定的策略。这里实现了三种策略,即快速排序、堆排序和合并排序。

策略模式在java集合中的TreeSet和TreeMap中得到了很好的应用,我们可以实现Comparator接口实现Compareto()方法来定义自己的排序规则,然后通过TreeSet,TreeMap构造方法传入实现该接口的实例,map中的顺序就会是我们自定义的顺序。我们可以完全定义自己的规则,用之极为方便。那么,什么是策略模式呢?

策略模式定义:定义一组算法,将每个算法都封装起来,并且使它们之间可以转换。策略模式使这些算法在客户端调用时能够互不影响的变化。

策略模式组成:

1.抽象的策略角色:策略类,通常由一个抽象类或者接口实现。

2.具体的策略角色:包装了相关的算法和行为。

3.环境角色:持有一个策略类的引用,以便最终给客户端调用。

策略模式的设计原则:

1.封装变化

2.使用接口编程

策略模式的实现:

1.将每一组算法封装到具有共同接口的独立类中,这样不同的策略可以相互替换

2.算法可以在不影响客户端的情况下发生变化,把行为和环境分开。

3.环境类负责维持和查询行为类,各种算法在具体策略中提供

看文字看蒙了,举一个具体的例子吧,举什么例子呢?想到我们数据结构中的各种排序,什么冒泡排序,快速排序,堆排序...,他们完成的功能都是一样的,只是排序算法不同而已。我们就可以看成是排序的不同策略。

首先定义我们的抽象策略:

/*** 抽象的策略类
 * @author*
 */
public interfaceStrategy {
    
    public void sort(int[] array);
}
View Code

定义具体的策略,这里实现了三种策略,分别是快速排序,堆排序,归并排序。

快速排序策略代码:

public class QuickSort implementsStrategy{

    @Override
    public void sort(int[] array) {
        qpSort(array,0,array.length - 1);
    }
    
    private void qpSort(int array[], int low, inthigh) {
        int pos = qkPass(array, low, high); //产生中间第一个确定的数

        if (low <high) {
            qpSort(array, low, pos - 1);//左边
            qpSort(array, pos + 1, high);//右边
}
    }

    private  int qkPass(int a[], int low, inthigh) {
        int x =a[low]; 

        while (low <high) {

            while (low < high && a[high] >x) {
                high--;
            }
            if (low <high) {
                a[low] =a[high];
                low++;
            }
            while (low < high && a[low] <x) {
                low++;
            }
            if (low <high) {
                a[high] =a[low];
                high--;
            }
        }
        a[low] =x;

        returnlow;
    }
    
}
View Code

堆排序策略代码:

public class HeapSort implementsStrategy {

    @Override
    public void sort(int[] array) {
        heapSort(array,array.length);
    }

    private void heapSort(int a[], intlength) {

        crtHeap(a, length); //创建大根堆

        for (int i = length - 1; i > 0; i--) {

            int b = a[0];

            a[0] = a[i]; //堆顶跟堆尾互换
a[i] =b;

            sift(a, 0, i - 1); //使得r[0...i-1]变成堆
}
    }

    /*** 建立初堆
     * 
     * @parama
     *            为带排序的数组
     * @paramlength
     *            为数组长度
     */
    private void crtHeap(int a[], intlength) {

        int n = length - 1;

        //建出堆,从第 n/2 个记录开始进行堆筛选
        for (int i = n / 2; i >= 0; i--) {

            sift(a, i, n);
        }
    }

    /*** 
     * @paramr
     *            数组
     * @paramk
     *            表示以r[k]为根的完全二叉树,调整r[k],使得r[k...m]满足大根堆的性质
     * @paramm
     *            堆尾元素下标
     */
    private void sift(int r[], int k, intm) {

        int temp = r[k]; //暂存根记录

        int i = k; //记录初始根的下标

        int j = i * 2 + 1; //根的左孩子,因为下标从0开始

        while (j <=m) {
            //如果存在右子树,且右子树根的关键字大,则沿右分支筛选,否则沿左分支筛选。因为目的是找一个最大的元素
            if (j < m && r[j] < r[j + 1]) {
                j = j + 1;
            }

            if (temp >=r[j]) {
                break; //结束筛选
}
            else{
                r[i] = r[j]; //上移
                i = j; //从新定义根下标
                j = j * 2 + 1;//继续筛选
}
        }

        r[i] = temp; //将r[k]移动到适当的位置
}

}
View Code

归并排序策略代码:

public class MergeSort implementsStrategy{

    @Override
    public void sort(int[] array) {
        int[] temp = new int[array.length];
        mSort(array,0,array.length - 1, temp);
    }
    
    /*** 
     * @paramr1 等待排序数组
     * @paramlow 
     * @paramhigh
     * @paramr3  将r1排序后的结果放在r3中 r1[low...high],r3[low...high]
     */
    private void mSort(int r1[],int low,int high, intr3[]){
        
        
        
        if(low  <high)
        {
            int mid = (low + high) /2;
            
            //归并排序中 拆,合要一起进行
mSort(r1,low,mid,r3);
            
            mSort(r1,mid+1,high,r3);
            
            merge(r1,low, mid, high, r3);
        }
        
    }
    
    private void merge(int r1[],int low, int mid, int high, intr2[]){
        
        int i =low;
        int j = mid + 1;
        int k = 0;
        
        while(i <=mid && j <=high){
            
            if(r1[i] <=r1[j]){
                r2[k] =r1[i];
                i++;
            }
            else{
                r2[k] =r1[j];
                j++;
            }
            
            k++;
        }
        
        while(i <=mid){
            r2[k] =r1[i];
            i++;
            k++;
        }
        
        while(j <=high){
            r2[k] =r1[j];
            j++;
            k++;
        }
        
        for(int m = 0; m < k;m++){
            r1[low + m] =r2[m];
        }
    }

}
View Code

定义环境类:

public classEnvironment {
    
    private Strategy strategy; //策略类的引用
    
    publicEnvironment(Strategy strategy){
        this.strategy =strategy;
    }
    
    //用于设置不同的策略
    public voidsetStrategy(Strategy strategy){
        this.strategy =strategy;
    }
    
    //实现排序的功能
    public void sort(intarray[]){
        strategy.sort(array);
    }
    
}
View Code

最后定义客户端类:

public classClient {
    
    public static voidmain(String[] args) {
        
        int[] array1 = new int[]{48,62,35,77,55,14,35,98};
        int[] array2 = new int[]{48,62,35,77,55,14,35,98};
        int[] array3 = new int[]{48,62,35,77,55,14,35,98};
        
        
        //使用堆排序策略
        Environment env = new Environment(newHeapSort());
        
        env.sort(array1);
        System.out.println("使用堆排序array1:");
        print(array1);
        
        //使用快速排序策略
        env.setStrategy(newQuickSort());
        env.sort(array2);
        System.out.println("使用快速排序array2:");
        print(array2);
        
        //使用归并排序策略
        env.setStrategy(newMergeSort());
        env.sort(array3);
        System.out.println("使用归并排序array3:");
        print(array3);
        
    }
    
    static void print(int[] array){
        for(int i = 0; i < array.length; i++){
            System.out.print(array[i] + "	");
        }
        System.out.println();
        System.out.println("---------------------------------");
    }
}
View Code

运行结果如下所示:

策略模式(strategy pattern)第1张

我们使用不同的排序策略分别对三个数组排序的功能已经实现了,程序非常灵活,我们想用什么策略来实现排序可以自己决定(通过environment.serStrategy(XXX)方法)。

程序中Environment类根本不知道也不用管排序到底是怎么实现的,它只是持有一个具体策略类的引用,然后调用具体策略类的方法。

策略模式用着很方便,但是本身也有缺点:

1.客户端必须知道所有的策略类,并自行决定使用哪种策略类。

2.造成很多的策略类,每一个不同的策略都需要一个策略类来实现。

对于第一点很明显,我们客户端(client类)在使用策略时必须知道具体的策略类是什么,environment.serStrategy(XXX)方法也需要知道。

对于第二点,定义了3中策略,就有3个策略类,如果策略很多的话,类也会很多。

参考资料:圣思园教学视频

免责声明:文章转载自《策略模式(strategy pattern)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇ubuntu16.04更换成国内源MySql报错-Data truncation: Data too long for column 'XXX' at row 1下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

DDD:策略模式如何结合动态表达式

企业应用中我们经常会遇到各种业务规则,针对这种规则,我们多数情况会采用策略模式,每种策略对应一个具体类和一个具体的配置界面。但是企业业务的规则经常变化,现有的策略随着时间的推移而不能满足要求,针对这种情况我们可以用动态表达式来解决。 动态表达式:在静态语言中动态的执行代码,目前可选的技术有:动态编译、Iron、Roslyn、内嵌小语言。 今天来测试一下内嵌...

Linux多网卡负载均衡 : bond

USERCTL=no/yes 普通用户是否可以关闭或启用网关 -------------------------------- 在这介绍的Linux双网卡绑定实现就是使用两块网卡虚拟成为一块网卡,这个聚合起来的设备看起来是一个单独的以太网接口设备,通俗点讲就是两块网卡具有相同的IP地址而并行链接聚合成一个逻辑链路工作。其实这项技术在Sun和Cisco中早已...

LVS分析

概述 LVS是章文嵩博士十几年前的开源项目,已经被何如linux kernel 目录十几年了,可以说是国内最成功的kernle 开源项目, 在10多年后的今天,因为互联网的高速发展LVS得到了极大的应用, 是当今国内互联网公司,尤其是大型互联网公司的必备武器之一, 从这一点上来说,LVS名副其实。搞了这么多年linux 网络开发维护, 由于一直偏通信方向,...

java 策略模式

定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。 类型:行为类模式 类图:        策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换。在前面说过的行为类模式中,有一种模式也是关注对算法的封装——模版方法模式,对照类图可以看到,策略模式与模版方法模式的区别仅仅是多了一个单独的封装...

C#设计模式总结(转)

一、引言   经过这段时间对设计模式的学习,自己的感触还是很多的,因为我现在在写代码的时候,经常会想想这里能不能用什么设计模式来进行重构。所以,学完设计模式之后,感觉它会慢慢地影响到你写代码的思维方式。这里对设计模式做一个总结,一来可以对所有设计模式进行一个梳理,二来可以做一个索引来帮助大家收藏。   PS: 其实,很早之前我就看过所有的设计模式了,但是...

1.2 备份与恢复基础

备份(backup)实际就是数据的副本,备份的目的是为了防止不可预料的数据丢失和应用错误。 转储(restore)是指当数据文件或控制文件出现损坏时,将已备份的副本文件还原到原数据库的过程。 恢复(recover)是指应用归档日志和重做日志事务更新副本文件到数据文件失败前的状态。 1.2.1 备份与恢复方法  1,用户管理的备份与恢复 用户管理的备份与恢复...