策略模式
介绍
定义一组算法,将每个算法都封装起来,并且使它们之间可以相互转换。策略模式让算法独立于使用它的客户而变化。
优点和体现的设计原则:
- 把变化的代码从不变的代码中分离出来,使算法可以自由切换
- 针对接口编程而不是具体类,体现了开闭原则
- 多用组合、聚合,少用继承
- 封装隐藏了复杂的算法代码
缺点:
- 容易产生过多的类,不容易维护
- 所有策略类都需要对外暴露
注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
原理和角色
这个类图和状态模式很像
策略模式与状态模式
状态模式是根据状态来决定行为,不同状态之下会采取一系列不同的行为(所有的方法的实现都可能发生变化)
但策略模式没有状态的概念,它直接关注于行为的实现方案(某一个行为的具体执行过程),更多地关注的是项目中变化与不变的部分。
比如,在状态模式下,如果我今天的状态是“不开心”,那么我起床、吃饭、读书、睡觉等一系列行为都会受到影响
但是策略模式仅关注某一个行为的具体执行过程,比如我读书怎么读?站着坐着还是躺着?
此外,状态模式涉及到状态变化,状态变化才会导致行为变化。而状态可以因为外部刺激而变化,也会因为内部的行为而变化,此时完全不需要客户端进行感知。但对于策略模式,其策略必须由调用方(客户)指定。
因此,两个模式的关注点并不相同
当一个系统有许多许多类,而区分它们的只是他们直接的行为时,就应该用策略模式
应用
ThereadPoolExecutor的拒绝执行策略
ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue<Runnable>, RejectedExecutionHandler)
中,RejectedExecutionHandler参数是一个拒绝执行策略参数,其有以下四种实现
Arrays.sort和Comparator
Comparator接口可以指定一种比较方式,可以视为策略接口:
Comparator<Integer> comparator = new Comparator<> {
// 下面这个可以视为策略方法,实现了具体的操作策略。(注:也可以用lambda实现)
@Override
public int compare(Integer o1, Integer o2) {
// 降序
return o2 - o1;
}
}
// Arrays.sort方法传入待排序数据,还可以传入一个比较策略
Arrays.sort(data, comparator);