算法与对象的耦合
对象可能经常需要使用多种不同的算法,但是如果变化频繁,会将类型变得脆弱。
动机(Motivation)
在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使得对象变得异常复杂;而且有时候支持不适用的算法也是一个性能负担。
如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
意图(Intent)
定义一系列算法,把他们一个个封装起来,并且使它们可互相替换。该模式使得算法可独立于使用它的客户而变化。
结构(Structure)
-
Context:封装角色 它也叫上下文角色,起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
-
Strategy:抽象策略角色 策略。算法家族的抽象,通常为接口。
-
ConcreteStrategy:具体策略角色 实现抽象策略中的操作,该类含有具体的算法。
理解锦囊妙计例子,锦囊对应Context ,妙计对应ConcreteStrategy 。
Strategy模式的几个要点
-
Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。所谓封装算法,支持算法的变化。
-
Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。
-
与State模式类似,如果Strategy对象没有实力变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。
缺点: 策略类数量增多,每一个策略都是一个类,复用的可能性很小。 所有的策略类都需要对外暴露。
策略模式和代理模式的差别就是:策略模式的封装角色和被封装的策略类不用是同一个接口,如果是同一个接口那就成为了代理模式。
示例代码
抽象的策略角色:
public interface Strategy{
//策略模式的运算法则
public void doSomething();
}
具体策略角色:
public class ConcreteStrategy1 implements Strategy{
public void doSomething(){
System.out.println("具体策略1的运算法则");
}
}
public class ConcreteStrategy2 implements Strategy{
public void doSomething(){
System.out.println("具体策略2的运算法则");
}
}
封装角色:
public class Context{
//抽象策略
private Strategy strategy = null;
//构造函数设置具体策略
public Context(Strategy strategy){
this.strategy = strategy;
}
//封装后的策略方法
public void doAnything(){
this.strategy.doSomething();
}
}
场景类:
public class Client{
public static void mian(String[] args){
//声明一个具体的策略
Strategy strategy = new ConcreteStrategy1();
//声明上下文对象
Context context = new Context(strategy);
//执行封装后的方法
context.doAnything();
}
}