策略模式
描述
定义一组策略,并将其封装起来到一个策略上下文中。
由调用者决定应该使用哪种策略,并且可以动态替换
基本使用
- 定义策略接口
java
public interface IStrategy {
void action();
}
- 声明具体策略类
java
public class StrategyA implements IStrategy {
@Override
public void action() {
System.out.println("策略A.....");
}
}
public class StrategyB implements IStrategy {
@Override
public void action() {
System.out.println("策略B.....");
}
}
- 定义策略上下文(调用方通过上下文发起策略调用)
java
public class StrategyContext {
private IStrategy strategy;
public StrategyContext(IStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(IStrategy strategy) {
this.strategy = strategy;
}
public void doAction() {
strategy.action();
}
}
使用
调用方选择一个策略,并创建策略上下文 发起调用
java
public class Sample {
public static void main(String[] args) {
IStrategy strategyA = new StrategyA();
// 初始化时持有策略A
StrategyContext context = new StrategyContext(strategyA);
context.doAction();
System.out.println("===== 替换策略 ====");
// 动态替换为策略B
IStrategy strategyB = new StrategyB();
context.setStrategy(strategyB);
context.doAction();
}
}
传统策略模式的缺陷以及规避方法
和工厂模式中子工厂数量过多的问题一致。当策略数量变多时,会对调用方不够友好,调用方并不想了解具体策略的实现
我们可以参考工厂模式的处理方式:引入一个协调类对所有策略进行管理
- 定义一个协调类(将所有策略管理起来,具体方案多种多样)
java
public final class StrategyFactory {
private static Map<String, IStrategy> strategyMap = new HashMap<>();
static {
strategyMap.put("A", new StrategyA());
strategyMap.put("B", new StrategyB());
}
public static IStrategy getInstance(String code) {
return strategyMap.get(code);
}
}
- 将具体策略的选择放到策略上下文中,根据调用方传入的标识选择对应的策略
java
public class StrategyContextV2 {
private IStrategy strategy;
public StrategyContextV2(String code) {
this.strategy = StrategyFactory.getInstance(code);
}
public void setStrategy(String code) {
this.strategy = StrategyFactory.getInstance(code);
}
public void doAction() {
strategy.action();
}
}
- 使用(调用方只需传入策略标识,可以调用对应策略。调用方对具体策略无感知)
java
public class SampleV2 {
public static void main(String[] args) {
StrategyContextV2 contextV2 = new StrategyContextV2("A");
contextV2.doAction();
System.out.println("===== 替换策略 ====");
contextV2.setStrategy("B");
contextV2.doAction();
}
}
枚举策略
描述
基于以上传统策略中使用协调类来规避具体策略对调用方的影响考虑。
总的来说,这就是一种表驱动的思想。将一些控制逻辑抽离为一些特定的数据结构(不限于数组 、字典 、外部配置文件等等)
Java中的枚举就是一种自带表驱动属性的数据类型
基本使用
- 定义策略枚举
java
public enum StrategyEnum {
A("A策略") {
@Override
public void action() {
System.out.println("调用策略A.....");
}
},
B("B策略") {
@Override
public void action() {
System.out.println("调用策略B.....");
}
},
;
/**
* 策略描述
*/
private final String desc;
StrategyEnum(String desc) {
this.desc = desc;
}
public abstract void action();
}
- 定义策略枚举上下文
java
public class StrategyContext {
public static void doAction(String code) {
StrategyEnum.valueOf(code).action();
}
}
使用
同样只需传入策略标识即可
java
public class Sample {
public static void main(String[] args) {
StrategyContext.doAction("A");
StrategyContext.doAction("B");
}
}
可以看到,使用枚举实现似乎更加简单