策略模式(Strategy Pattern)

1. 什么是策略模式?

策略模式(Strategy Pattern) 是一种行为型设计模式,通过定义一组可互换的算法族,并将每个算法封装成独立类,使得算法可以独立于客户端变化。其核心是
将算法与使用场景解耦,避免复杂的条件分支,提升系统扩展性。

📜 设计原则体现
符合 开闭原则(新增策略无需修改已有代码)、单一职责原则(每个策略类只负责一个算法)


2. 核心思想

核心点 说明
算法抽象化 通过接口定义算法规范,隐藏具体实现细节
动态替换 运行时通过注入不同策略对象切换算法(如:设置不同的折扣策略)
消除条件分支 用多态代替 if-else/switch-case,使代码更简洁

3. 代码案例

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
44
45
46
47
48
49
50
// filepath: 示例代码
// 1. 策略接口(定义算法规范)
public interface DiscountStrategy {
void applyDiscount(double price);
}

// 2. 具体策略实现
public class NineDiscount implements DiscountStrategy {
@Override
public void applyDiscount(double price) {
System.out.printf("[9折] 折后价: %.2f\n", price * 0.9);
}
}

public class EightDiscount implements DiscountStrategy {
@Override
public void applyDiscount(double price) {
System.out.printf("[8折] 折后价: %.2f\n", price * 0.8);
}
}

// 3. 上下文类(组合策略)
public class PriceCalculator {
private DiscountStrategy strategy;

// 策略注入方式(构造器注入)
public PriceCalculator(DiscountStrategy strategy) {
this.strategy = strategy;
}

// 动态切换策略
public void setStrategy(DiscountStrategy strategy) {
this.strategy = strategy;
}

public void calculate(double price) {
strategy.applyDiscount(price);
}
}

// 4. 客户端调用
public class Client {
public static void main(String[] args) {
PriceCalculator calculator = new PriceCalculator(new NineDiscount());
calculator.calculate(100); // 输出 9 折价格

calculator.setStrategy(new EightDiscount());
calculator.calculate(100); // 动态切换为 8 折
}
}

4. 类结构图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
+---------------------+
| DiscountStrategy |<-----------------------------+
+---------------------+ |
| + applyDiscount() | |
+---------------------+ |
▲ |
| |
+---------------------+ +---------------------+ |
| NineDiscount | | EightDiscount | |
+---------------------+ +---------------------+ |
| + applyDiscount() | | + applyDiscount() | |
+---------------------+ +---------------------+ |
▲ |
| |
+---------------------+ |
| PriceCalculator |-------------------------------+
+---------------------+
| - strategy |
| + setStrategy() |
| + calculate() |
+---------------------+

5. 模式优势

优势 说明
高扩展性 新增策略只需实现接口,无需修改上下文类
算法复用 同一策略可被多个上下文复用(如不同模块使用相同折扣逻辑)
提升可维护性 算法变化被隔离在策略类中,降低对整体系统的影响
简化单元测试 每个策略可独立测试,无需耦合客户端逻辑

6. 注意事项

6.1 潜在问题

问题 解决方案
策略类数量膨胀 对简单策略使用 Lambda 或匿名类
客户端感知策略差异 结合工厂模式隐藏策略创建细节
策略无状态 将策略类设计为无状态对象,通过享元模式复用

6.2 最佳实践

  1. 优先组合而非继承:通过将策略接口组合到上下文中,而非使用继承层次。
  2. 与工厂模式结合:用 StrategyFactory 管理策略对象的创建逻辑。
  3. 策略命名规范化:使用 XxxStrategy 后缀提高代码可读性(如 PaymentStrategy)。

7. 实际应用场景

  • 支付系统:切换不同的支付方式(支付宝、微信、信用卡)。
  • 游戏 AI:根据敌人类型切换攻击策略。
  • 数据解析:支持 JSON、XML、CSV 等多种格式解析。
  • Spring 框架ResourceLoader 的资源加载策略、PlatformTransactionManager 的事务管理策略。

8. 附录

8.1 参考资料

8.2 延伸阅读