引:将所有方法封装起来,要用什么方法就打开什么方法,这就是策略模式。
定义
定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。——行为类
我们先看它的类图:
简单介绍类图中的几个类:
- Context封装角色,也叫上下文角色,起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问。
- Strategy抽象策略角色,定义每个策略或算法必须具有的方法和属性。
- ConcreteStrategy具体策略角色,实现抽象策略的操作,该类含有具体的算法。
下面是它的通用源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43// 抽象的策略角色
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 doAngthing() {
this.strategy.doSomething();
}
}
// 场景类
public class Client {
public static void main(String[] args) {
// 声明一个具体的策略
Strategy strategy = new ConcreteStrategy1();
// 声明上下文对象
Context context = new Context(strategy);
// 执行封装后的方法
context.doAngthing();
}
}
策略模式实质是采用了面向对象的继承和多态机制。但是一个类实现多个接口很正常,所以识别出抽象策略接口是系统分析师的价值所在。策略模式和代理模式的区别是策略模式的封装角色和被封装的策略类不用是同一个接口。
应用
优点
- 算法可以自由切换
- 避免使用多重条件判断
- 扩展性良好
缺点
- 策略类数量增多,复用可能性小
- 所有策略类都需要对外暴露,上层模块需要知道有哪些策略,违背了迪米特法则
使用场景
- 多个类只有在算法或行为上稍有不同的场景
- 算法需要自由切换的场景
- 需要屏蔽算法规则的场景
注意事项
如果系统中的一个策略家族的具体策略数量超过4个,则需要考虑使用混合模式,解决策略类膨胀和对外暴露问题。
最佳实践
策略模式在项目中会经常使用,但是它具有一个致命缺陷:所有的策略都需要暴露出去。在实际项目中,我们一般通过工厂方法模式来实现策略类的声明。
参考
- 《设计模式之禅》