从北京到上海,可以坐高铁,可以坐绿皮,可以自己开车,也有个别人可能选择步行的方式。总之就是有很多种方式可以供我们选择,选择的方式不同,过程不同,但结果都是一样的,都可以从北京到上海,只要选择适合的就可以了,高铁贵但快,绿皮便宜但慢,自己开车累但方便。
在开发中也经常碰到这种情况,例如要对一个数组进行排序,可选择不同的方法:冒泡啦、选择啦、快排啦、归并啦、插入等等;例如要对一张图片进行滤波处理,也有不同的选择:高斯滤波、中值滤波、 均值滤波、双边滤波等等。
上面的例子在编码中使用if-else可以很简单的实现了,但如果喷到解决方案中每一个方法都包括了大量的处理逻辑,或者处理方式变动较大的时候,代码看起来就会显得杂乱不堪,难以理解。策略模式就可以避免这种情况,它将各种方案分离开来封装到每一个具体类中,让操作者根据具体的需求来动态的选择不同的策略方案。
定义:
定义一组策略,将每一个策略封装起来,并使他们能够相互替换。
结构:
- 封装类:对策略进行二次封装,避免高层模块对策略的直接调用,持有一个Strategy的引用
- 抽象策略:由接口或者抽象类实现。给出所有具体策略类所需的接口
- 具体策略:具体策略的实现。
适用场景:
- 针对同一类型问题的多种处理方法
- 需要安全的封装多种同一类型的操作时
- 出现同一抽象的多个子类,又需要if-else或者switch-case来选择时
UML类图:
下面时策略模式的代码实现:
Context(封装类):
public class Context {
private Strategy strategy;
public void setStrategy(Strategy strategy){
this.strategy = strategy;
}
public void execute(){
strategy.executeStrategy();
}
}
Strategy(策略)
public interface Strategy {
void executeStrategy();
}
public class ConcreteStrategy1 implements Strategy{
@Override
public void executeStrategy() {
System.out.println("执行策略1");
}
}
public class ConcreteStrategy2 implements Strategy{
@Override
public void executeStrategy() {
System.out.println("执行策略2");
}
}
Test:
public class Test {
public static void main(String[] args){
ConcreteStrategy1 concreteStrategy1 = new ConcreteStrategy1();
ConcreteStrategy2 concreteStrategy2 = new ConcreteStrategy2();
Context context = new Context();
context.setStrategy(concreteStrategy1);
context.execute();
context.setStrategy(concreteStrategy2);
context.execute();
}
}
总结:策略模式的精髓不是如何实现不同的策略,而是如何组织、调用这些策略,从而让程序结构更灵活,便于维护和扩展,对策略的封装更为彻底,数据更安全。策略模式有两大特性:
1)策略的平等性:对于一系列策略,相互之间的地位完全一样,这样便可以实现策略的相互替换,策略之间没有相互的依赖。
2)运行时策略的唯一性:运行期间,在同一个时刻只能使用一个具体的策略实现对象。
策略模式的缺点也显而易见,调用者自行觉定使用哪一种策略,这意味着调用者必须理解这些策略的区别,以便选择适合的策略。
最后再来说说与策略模式极为相似的命令模式。他们都是将共性抽象出来并对一些行为进行封装,策略模式只是少了发送者和接收者,其他的实现几乎一模一样。他们的不同在于:
- 策略模式:不同的策略做同一件事情
- 命令模式:不同的命令做不同的事情
参考:http://www.cnblogs.com/java-my-life/archive/2012/05/10/2491891.html
https://github.com/simple-android-framework/android_design_patterns_analysis/tree/master/strategy/gkerison