您的位置:首页 > 编程语言 > Java开发

Java设计模式之策略模式

2017-02-23 20:46 218 查看

策略模式是项目中用得最多最广的一种模式了,从类图可以看出,他也相对是很简单的一种模式,那么什么是策略模式呢?

这里,我们不妨琢磨一下什么叫策略。。策略。。  what is Strategy!!!

小学的课文田忌赛马是不是策略?过年回家的方式算不算是策略?包括数学里多解法的应用题!还有银行理财的那些项目!这些都叫做策略,目的都很明确,他们都是为了完成某个功能或业务,而策略就是使用到的什么方法。

也就是说我们为了在程序中实现某一个功能,即便是最终实现的结果可能一致,但实现的细节各不相同,多多少少都可能影响系统业务或性能。所以有时需要在不同的时候改变不同的策略完成某个业务。

举例!比如我们要把十万个随机数进行排序,我们既可以选择冒泡排序,也可以选择堆排序,还可以选择希尔排序等等。

选择不同的方式虽然最终结果都可能一致,但是我们的效率却可能相差数十倍,所以针对不同的需求,我们可能需要随时更改计算策略。这时候你可能会想,既然堆排序那么快,那我们还要其他排序干什么呢?当然有必要,堆排序虽然快,但是针对十万个乃至百万个数,那么他的空间复杂度是非常庞大的,占用内存会比其他方式大得多得多。毕竟时间复杂度和空间复杂度总是成反比。如果你只想当做后台任务来计算,不在乎实时效率,那为嘛用堆排序来做!而且,如果这十万个数仅仅是前面100个被打乱了,后面的都已经是排好的,那么这个时候,冒泡(前提是加了锁旗标)的方式会比堆排序又快得多,而且S(n)和T(n)完胜堆排序,节省大量的时间和空间。所以,面对同样的问题,我们需要时刻改变策略来高效的完成任务。

下面是策略模式简单的类图:

在这里简单说一下,设计模式终究是一个面向对象的思想,对于初学者很难记住,即便学会了,但项目中长期不用很难再次想起,就算遇到了,也可能不认识了。所以在这里推荐大家最开始的时候用记类图的方式帮助快速掌握,因为类图是最接近面向对象的方式,能够清除的表达出代码结构,没听说过谁看着类图还写不出代码的。而且熟悉了类图的结构,以后在项目遇到某个模块使用了该模式,你也能快速的想起来这儿用到的是什么模式,加快对代码逻辑的理解。



从类图的结构上来说,很简单,一共就三个角色:

Context:上下文是依赖策略接口的类,上下文提供一个方法,该方法委托策略类调用具体策略所实现的策略接口中的方法。

Strategy:策略类 这是策略是一个接口,封装对具体策略要实现的方法。

ConcreteStrategy:具体策略类  具体策略实现策略接口所定义的抽象方法,即给出算法标识的具体算法。

下面用一个简单的示例来模拟一个简单的策略模式:

策略类:

public interface Strategy {
public int[] calculate(int a[]) ;
}


具体策略:
public class HeapStrategy implements Strategy{ //堆排序
@Override
public int[] calculate(int a[]) {
/**
* 堆排序的实现逻辑 代码太长已经屏蔽
*/
return a; //返回排好的数据
}
}

public class BubbleStrategy  implements Strategy{ //冒泡排序
    @Override
    public int[] calculate(int a[]) {
        int tem;
        for(int i=0;i<a.length-1;i++) {
            for (int j = 0; j < a.length - 1 - i; j++) {
                if (a[j] < a[j + 1]) {
                    tem = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = tem;
                }
            }
        }
        return a; //返回排好的数据
    }
}

上下文:

public class Context {
  Strategy strategy;
    int a[] = new int[100000]; //十万个数的数组
    public void setStrategy(Strategy strategy){ //传人一个实现排序功能的策略
        this.strategy = strategy;
    }
    public void sort(){ //开始执行排序任务
        long starTime=System.currentTimeMillis();
        a = strategy.calculate(a);
        long endTime = System.currentTimeMillis();
        System.out.println("本次算法花费时间" +(endTime-starTime)/1000 + "s");
    }

    public void getRandom(){ //生成十万个随机数
        for(int i = 0; i < 100000; i++){
            a[i] = (int) (Math.random()*100000);
        }
    }
}
测试类:
public class Main {
public static void main(String args[]){

Strategy bubbleStrategy = new BubbleStrategy();//冒泡策略
Strategy heapStrategy = new HeapStrategy();//堆策略

Context context = new Context();
context.getRandom();
context.setStrategy(bubbleStrategy);
context.sort();// 打印出冒泡排序十万个数的耗时

context.getRandom();
context.setStrategy(heapStrategy);
context.sort();//打印出堆排序十万个数的耗时
}
}
结果


虽然Context的任务就是排序,但是给它传入两套不同的方案却能提高不少效率,这就是策略模式的好处。

如果现在有一个需求,一个app系统有多套登录方式(比如:单点登录,微信登录,QQ登录、支付宝),然后获取登录后的返回结果(User对象),这个时候我们就可以选择策略模式了,调用login(LoginStrategy strategy)方法,传入具体的策略,每个登录方式自己去实现登录细节,然后把数据封装到User里返回,这样对于客户端就可以整洁的完成登录功能了,如果PM下达需求,再增加一个微博登录,你再实现一个WeiboStrategy不就可以了吗。无需修改Context的代码,用户点击哪种方式,你传入对应的策略就OK!是不是很简单!

其实我们实际项目中应该有这么写过,可能当时还不知道这就是策略模式。以后遇到这样的需求,尽量这么写,提升代码质量。增加可读性,别人维护的时候也会轻松容易。

最后在总结一下策略模式有什么优点:

1.很明显 ,上下文(Context)和具体策略(ConcreteStrategy)是松耦合的关系,因此,上下文只知道他要使用某一个实现Strategy接口类的实例,但不需要知道具体是哪一个类。

2.策略模式满足“开闭原则”,当增加新的具体策略时,不需要修改上下文类的代码,上下文就可以引用新的具体策略的实例。这就是多态的好处,说白了,之所以有设计模式的存在,肯定跟多态离不开关系,23个设计模式中除了单例和状态模式(如果没记错的话),其他都离不开多态,设计模式的核心就是用抽象类和接口去替代具体实现类的引用,以达到解耦的目的,通过子类的实现去完成业务功能,而整个项目结构去不受影响,功能还能无线扩充,层次清晰。高质量的代码离不开设计模式,同时它也是学会架构的基础。




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息