策略模式,是11种行为型模式之一。在 GoF 的《设计模式》一书中,它是这样定义的:Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.翻译成中文就是:定义一系列算法(策略),封装每一个算法(策略),并使它们可以互换。使算法(策略)可以独立于使用它的客户端(调用者)而变化。
策略模式分为简单策略模式和复合策略模式。简单策略模式跟桥接模式一样,但应用场景不同。复合策略模式是为了让策略可以运行时动态调用而混合工厂模式。不多说看先看代码。
未使用策略模式:
class Client {
String type;
Client(String type) {
this.type = type;
}
public String operate() {
String result = null;
if("A".equals(type)) {
//省略代码 策略A
} else if("B".equals(type)) {
//省略代码 策略B
} else {
//省略代码 策略B
}
return result;
}
}
简单策略模式:
interface Strategy {
public String operate(省略参数);
}
//A策略
class AStrategy {
public String operate(省略参数){
//省略代码
}
}
//省略BStrategy CStrategy
class Client {
Strategy strategy;
Client(Strategy strategy){
this.strategy = strategy;
}
public String operate() {
return strategy.operate(省略参数)
}
}
class Demo {
public static void main(String[] args) {
Client client = new Client(new AStrategy());
System.out.println("a = " + client.operate());
client = new Client(new BStrategy());
System.out.println("b = " + client.operate());
}
}
简单策略模式需要调用者事先选择策略,如果要换策略,需要修改代码。不能根据代码的情况动态选择策略。
所谓动态选择策略就是可以在程序运行期间,根据配置、用户输入、计算结果等这些不确定因素,动态决定使用哪种策略。既然是动态的使用策略,就需要动态的创建策略。动态的创建对象使用工厂模式最合适不过了。
//省略策略定义
//如果策略类是无状态的,使用下面缓存方式共享策略
public class StrategyFactory {
private static final Map<String, Strategy> strategies = new HashMap<>();
static {
strategies.put("A", new AStrategy());
strategies.put("B", new BStrategy());
}
public static Strategy getStrategy(String type) {
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type should not be empty.");
}
return strategies.get(type);
}
}
或者
//如果策略类是有状态的,使用每次创建新策略的方式
public class StrategyFactory {
public static Strategy getStrategy(String type) {
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type should not be empty.");
}
if (type.equals("A")) {
return new AStrategy();
} else if (type.equals("B")) {
return new BStrategy();
}
return null;
}
}
// 非运行时动态确定,在代码中指定使用哪种策略
public class Demo{
public static void main(String[] args) {
Strategy strategy = new BStrategy();
Client client = new Client(strategy);
System.out.println(client.operate());
}
}
// 运行时动态确定,根据配置文件的配置决定使用哪种策略
public class Demo{
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.load(new FileInputStream("./config.properties"));
String type = props.getProperty("strategy_type");
Strategy strategy = StrategyFactory.getStrategy(type);
Client client = new Client(strategy);
System.out.println(client.operate());
}
}
策略模式遵循的设计原则和思想:
- 面向接口编程的思想:把策略抽象成接口;
- 多用组合少用继承的思想:调用者以聚合方式的使用策略;
- 单一职责原则:把策略代码提取到单独的策略类,策略类和调用者的职责更加单一;
- DRY原则:把策略代码提取到单独的策略类,可以重复使用;
- 开闭原则:把策略与调用者解耦,使用策略可以单独扩展,而不影响调用者;