基本概念
策略模式(Strategy Pattern):一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。策略模式的本质:分离算法,选择实现。
策略模式的优点
- 策略模式的功能是通过策略上下文(Context )来抽象、封装和分离,定义一系列的算法对应的策略,使得这些算法策略可以相互替换,所以为这些算法定义一个公共的接口(IStrategy),以约束这些算法的功能实现。如果这些算法具有公共的功能,可以将接口变为抽象类,将公共功能放到抽象父类里面。
- 策略模式的一系列算法是可以相互替换的、是平等的,写在一起就是if-else组织结构,如果算法实现里又有条件语句,就构成了多重条件语句,可以用策略模式,避免这样的多重条件语句。
- 扩展性更好:在策略模式中扩展策略实现非常的容易,只要新增一个策略实现类,然后在使用策略实现的地方,使用这个新的策略实现就好了。
- 策略模式体现了开闭原则:策略模式把一系列的可变算法进行封装,从而定义了良好的程序结构,在出现新的算法的时候,可以很容易的将新的算法实现加入到已有的系统中,而已有的实现不需要修改。
- 策略模式体现了里氏替换原则:策略模式是一个扁平的结构,各个策略实现都是兄弟关系,实现了同一个接口或者继承了同一个抽象类。这样只要使用策略的客户端保持面向抽象编程,就可以动态的切换不同的策略实现以进行替换。
代码实现如下:
package com.test.design.pattern;
/**
* Created by Administrator
* on 2019/12/20.
*/
public class StrategyTest {
/**
* 策略接口
*/
public interface IStrategy {
void testStrategy();
}
/**
* 策略接口实现:打印策略
*/
public static class PrintStrategy implements IStrategy {
public void testStrategy() {
System.out.print("我要打印!!");
}
}
/**
* 策略接口实现:写字策略
*/
public class WriteStrategy implements IStrategy {
public void testStrategy() {
System.out.println("我要写字!!!");
}
}
/**
* 策略执行上下文
*/
public static class Context {
private IStrategy stg;
Context(IStrategy theStg) {
this.stg = theStg;
}
void doAction() {
this.stg.testStrategy();
}
}
public static void main(String[] args) {
//客户端通过上下文调用策略
IStrategy stgA = new PrintStrategy();
Context ct = new Context(stgA);
ct.doAction();
}
}
策略模式在JDK线程池中的应用:
具体可以参考 RejectedExecutionHandler 接口和实现类。
策略上下文的作用
上下文持有策略的引用,以进行对具体策略的调用。如果没有上下文(Context)的话,客户端就必须直接和具体的策略实现进行交互了,尤其是需要提供一些公共功能或者是存储一些状态的时候,会大大增加客户端使用的难度;引入上下文之后,这部分工作可以由上下文来完成,客户端只需要和上下文进行交互就可以了。这样可以让策略模式更具有整体性,客户端也更加的简单。
使用限制:
- 客户端必须了解所有的策略,清楚它们的不同,如果由客户端来决定使用何种算法,那客户端必须知道所有的策略,清楚各个策略的功能和不同,这样才能做出正确的选择,但是这暴露了策略的具体实现。
- 只适合偏平的算法结构,由于策略模式的各个策略实现是平等的关系(可相互替换),实际上就构成了一个扁平的算法结构。即一个策略接口下面有多个平等的策略实现(多个策略实现是兄弟关系),并且运行时只能有一个算法被使用。这就限制了算法的使用层级,且不能被嵌套。
- 增加了对象的数量,由于策略模式将每个具体的算法都单独封装为一个策略类,如果可选的策略有很多的话,那对象的数量也会很多。