策略模式(Strategy Pattern)是一种比较简单的模式,也叫做政策模式(Policy Pattern)。其定义如下:
Define a family of algorithms,encapsulate each one,and make them interchangeable.(定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。)
这个定义是非常明确、清晰的,“定义一组算法”,看看我们的三个计谋是不是三个算法?“将每个算法都封装起来”,封装类Context不就是这个作用吗?“使它们可以互换”当然可以互换了,都实现是相同的接口,那当然可以相互转化了。我们看看策略模式的通用类图,如图18-3所示。
图18-3 策略模式通用类图
策略模式使用的就是面向对象的继承和多态机制,非常容易理解和掌握,我们再来看看策略模式的三个角色:
● Context封装角色
它也叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
● Strategy抽象策略角色
策略、算法家族的抽象,通常为接口,定义每个策略或算法必须具有的方法和属性。各位看官可能要问了,类图中的AlgorithmInterface是什么意思,嘿嘿,algorithm是“运算法则”的意思,结合起来意思就明白了吧。
● ConcreteStrategy具体策略角色
实现抽象策略中的操作,该类含有具体的算法。
我们再来看策略模式的通用源码,非常简单。先看抽象策略角色,它是一个非常普通的接口,在我们的项目中就是一个普通得不能再普通的接口了,定义一个或多个具体的算法,如代码清单18-7所示。
代码清单18-7 抽象的策略角色
public interface Strategy { //策略模式的运算法则 public void doSomething;}
具体策略也是非常普通的一个实现类,只要实现接口中的方法就可以,如代码清单18-8所示。
代码清单18-8 具体策略角色
public class ConcreteStrategy1 implements Strategy { public void doSomething { System.out.println("具体策略1的运算法则"); }}public class ConcreteStrategy2 implements Strategy { public void doSomething { System.out.println("具体策略2的运算法则"); }}
策略模式的重点就是封装角色,它是借用了代理模式的思路,大家可以想想,它和代理模式有什么差别,差别就是策略模式的封装角色和被封装的策略类不用是同一个接口,如果是同一个接口那就成为了代理模式。我们来看封装角色,如代码清单18-9所示。
代码清单18-9 封装角色
public class Context { //抽象策略 private Strategy strategy = null; //构造函数设置具体策略 public Context(Strategy _strategy){ this.strategy = _strategy; } //封装后的策略方法 public void doAnythinig{ this.strategy.doSomething; }}
高层模块的调用非常简单,知道要用哪个策略,产生出它的对象,然后放到封装角色中就完成任务了,如代码清单18-10所示。
代码清单18-10 高层模块
public class Client { public static void main(String args) { //声明一个具体的策略 Strategy strategy = new ConcreteStrategy1; //声明上下文对象 Context context = new Context(strategy); //执行封装后的方法 context.doAnythinig; }}
策略模式就是这么简单,偷着乐吧,它就是采用了面向对象的继承和多态机制,其他没什么玄机。想想看,你真实的业务环境有这么简单吗?一个类实现多个接口很正常,你要有火眼金睛看清楚哪个接口是抽象策略接口,哪些是和策略模式没有任何关系,这就是你作为系统分析师的价值所在。