策略模式可以看做“可插入式算法(Pluggable)”,将子类各自的行为和公共的逻辑分离开来,将子类的行为抽象为算法插入到公共的逻辑中,这样替换子类的行为也不会对公共逻辑产生影响,也不会影响到调用类的逻辑。
下面是一个策略模式的简单例子,类图如下:
公共逻辑Context的代码如下:
public class Context{ public void contextInterface(){ //add common code here strategy.strategyInterface(); //add common code here } /** * @link aggregation * @directed */ private Strategy strategy; private void setStrategy (Strategy strategy){ this.strategy = strategy; } private Strategy getStrategy (){ return this.strategy; } }
子类算法的接口如下:
abstract public class Strategy{ public abstract void strategyInterface(); }
具体的算法如下:
public class ConcreteStrategy extends Strategy{ public void strategyInterface(){ //write you algorithm code here } }
当我们希望修改具体算法中的实现,我们只要重写一个类,继承Strategy接口,Context中的公共逻辑不需要修改。
Java中策略模式的例子:
环境角色由Container扮演,算法接口由LayoutManager扮演,具体算法由GridBagLayout、GridLayout等扮演。
Container中的代码:
if (layoutMgr != null) { if (layoutMgr instanceof LayoutManager2) { ((LayoutManager2)layoutMgr).addLayoutComponent(comp, null); } else { layoutMgr.addLayoutComponent(null, comp); } }
GridBagLayout中的addLayoutComponent方法的代码:
public void addLayoutComponent(Component comp, Object constraints) { if (constraints instanceof GridBagConstraints) { setConstraints(comp, (GridBagConstraints)constraints); } else if (constraints != null) { throw new IllegalArgumentException("cannot add to layout: constraints must be a GridBagConstraint"); } }
BorderLayout的addLayoutComponent方法的代码:
public void addLayoutComponent(Component comp, Object constraints) { synchronized (comp.getTreeLock()) { if ((constraints == null) || (constraints instanceof String)) { addLayoutComponent((String)constraints, comp); } else { throw new IllegalArgumentException("cannot add to layout: constraint must be a string (or null)"); } } }
还有一个很好的例子是系统要调用一种排序算法,可以是冒泡排序,快速排序等排序算法中的一种。应用策略模式可以很好的完成需求,并且维护性也很好。下面是类图:
客户端在调用Sorter时根据实际的需求传入BinSort或是BubbleSort等,这个决定应该是客户端来做的。
策略模式的优缺点如下:
优点:1.公共的逻辑被抽取到环境类中,避免了重复代码。
2.策略模式提供了比继承更为灵活的方式,较模板方式的灵活性要更高,子类对抽象算法的实现可以是完全不同的。
3.使用策略模式可以避免使用多重的条件判断语句来做逻辑。
缺点:1.客户端需要熟悉具体的算法子类以及自己需要调用哪一个算法子类。
2.策略模式可能会生成很多个的算法子类,可以使用享元模式来减少算法子类实例的个数。