策略模式(strategy pattern):定义一组算法,将每个算法都封装起来,并且使它们可以互换。策略模式使得算法可独立于它们的客户端而变化。
类图及角色
抽象策略角色:通常用一个类或接口来实现,主要定义这个算法所完成的功能。
具体策略角色:包装相关的算法和行为。
环境角色:持有策略类的引用。
策略模式的优点
- 算法可以自由切换,提供了管理相关算法族的办法。
- 避免使用多重条件判断语句。
- 提供了可替代继承关系的算法,扩展性良好。
策略模式的缺点
- 策略类会增多。
- 所有策略类都需要对外暴露,客户端必须知道所有的类。
策略模式的使用场合
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种,那么这些算法可以包装到一个个具体的算法类里,这些算法类都是抽象算法类的子类。
- 一个系统的算法使用的数据不可以让客户端知道。策略模式可以避免让客户端涉及到不必要接触到的复发和只与算法有关的数据。
如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
策略模式和状态模式的区别(孪生兄弟)
- 状态模式侧重状态方面,一般不会接受新的状态对象,即系统已经定义了足够的状态。
- 策略模式侧重不同行为的改变在统一的接口下。
- 状态模式中,状态的变迁由对象的内部条件决定;外部只关心接口,不关心其状态对象的创建和转化。
- 策略模式中采用何种策略由外部条件决定,也就是算法的动态切换。
策略模式和模板模式的区别
- 模板模式是算法在父类中(基本逻辑),子类不完全改写算法,可以改写部分,可以节省大量代码。
- 策略模式所有的算法均在子类中完成,强调行为即算法的不同。
- 模板方法使用继承来实现代码复用,策略模式使用委托,比继承有更大的灵活性。
public interface Strategy {
public void algorithmInterface();
}
public class Context {
Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
/**
* 上下文接口
*/
public void contextInterface() {
strategy.algorithmInterface();
}
}
class ConcreteStrategyA implements Strategy {
@Override
public void algorithmInterface() {
System.out.println("策略A的具体算法实现");
}
}
class ConcreteStrategyB implements Strategy {
@Override
public void algorithmInterface() {
System.out.println("策略B的具体算法实现");
}
}
class ConcreteStrategyC implements Strategy {
@Override
public void algorithmInterface() {
System.out.println("策略C的具体算法实现");
}
}
public class Client {
public static void main(String[] args) {
Context context;
context = new Context(new ConcreteStrategyA());
context.contextInterface();
context = new Context(new ConcreteStrategyB());
context.contextInterface();
context = new Context(new ConcreteStrategyC());
context.contextInterface();
}
}