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个设计模式中除了单例和状态模式(如果没记错的话),其他都离不开多态,设计模式的核心就是用抽象类和接口去替代具体实现类的引用,以达到解耦的目的,通过子类的实现去完成业务功能,而整个项目结构去不受影响,功能还能无线扩充,层次清晰。高质量的代码离不开设计模式,同时它也是学会架构的基础。
相关文章推荐
- Java设计模式 -- 策略模式
- [设计模式] - 策略模式(Java篇)
- Java设计模式-----Strategy策略模式
- 设计模式之三 --- 策略模式(Strategy Pattern) (java)
- java设计模式-策略模式
- java设计模式之 策略模式
- Java设计模式之策略模式
- 设计模式一:java设计模式之策略模式(一)
- java设计模式---Strategy Pattern---策略模式
- JAVA 设计模式之 策略模式
- java设计模式之strategy(策略模式)和policy模式(泛化的strategy模式)
- java 设计模式-策略模式
- Java设计模式 Design Pattern:策略模式 Strategy Pattern
- java设计模式--策略模式
- Java设计模式-----Strategy策略模式
- java设计模式-----策略模式
- All About JAVA 关于设计模式中的“策略模式”
- 设计模式:策略模式的实现 c++ 与 java
- java 设计模式--策略模式(strategy)
- java设计模式:策略模式(Strategy)