设计模式之分开考虑_Strategy策略模式_多个策略实现同一个接口
前言
Github:https://github.com/HealerJean
一、策略模式(Strategy Pattern)
1、模式概述
策略模式 是一种 行为型设计模式,它定义一系列 算法或行为,并将每一个算法封装起来,使它们可以 相互替换。策略模式让算法的变化 独立于使用它的客户端。
核心思想:“同一接口,多种实现 —— 行为可插拔。”
策略模式 = 行为抽象 + 实现分离:
- 它不是“写死逻辑”,而是“把变化的行为抽出来”,让系统更具弹性。
2、使用场景
策略模式适用于以下情况:
- 一个系统需要在运行时 动态选择多种算法之一;
- 多个类 仅在行为上不同,其余结构高度相似;
- 需要 避免使用多重条件判断语句(如
if-else或switch); - 希望 将行为逻辑从主业务中解耦,提高可测试性与可维护性。
典型例子:
- 电商订单计算运费(普通快递 / 顺丰 / 自提);
- 游戏角色攻击方式(近战 / 远程 / 魔法);
- 数据排序策略(升序 / 降序 / 自定义规则)。
在实际开发中:
Spring的HandlerMapping使用策略选择处理器;java.util.Comparator是策略模式的标准库实现;- 任何“同名不同行为”的场景,都是策略模式的用武之地。
3、示例程序:四则运算策略
- 客户端 直接或通过 Context 使用策略;
- 策略之间 完全独立,互不影响;
- 新增策略 无需修改原有代码(符合开闭原则)。
| 角色 | 职责 | 示例 |
|---|---|---|
| Strategy(策略接口) | 定义所有支持算法的公共接口 | Strategy |
| ConcreteStrategy(具体策略) | 实现 Strategy 接口,提供具体算法 | AddStrategy, SubStrategy |
| Context(上下文) | 持有 Strategy 引用,供客户端调用(可选但推荐) | 可封装策略切换逻辑 |
| Client(客户端) | 选择并使用具体策略 | Main |
1)策略接口 Strategy
/**
* 策略接口 —— 定义计算行为
*/
public interface Strategy {
String calculate(int a, int b);
}
2)具体策略实现
a、加法策略
public class AddStrategy implements Strategy {
@Override
public String calculate(int a, int b) {
return "a + b = " + (a + b);
}
}
b、减法策略
public class SubStrategy implements Strategy {
@Override
public String calculate(int a, int b) {
return "a - b = " + (a - b);
}
}
c、乘法策略
public class MulStrategy implements Strategy {
@Override
public String calculate(int a, int b) {
return "a * b = " + (a * b);
}
}
3)上下文封装(推荐增强版)
虽然策略模式不要求必须有 Context,但引入它可以 隐藏策略创建与切换细节。
import java.util.HashMap;
import java.util.Map;
/**
* 计算上下文 —— 封装策略选择逻辑
*/
public class Calculator {
private final Map<String, Strategy> strategies = new HashMap<>();
public Calculator() {
// 注册策略
strategies.put("add", new AddStrategy());
strategies.put("sub", new SubStrategy());
strategies.put("mul", new MulStrategy());
}
public String execute(String operation, int a, int b) {
Strategy strategy = strategies.get(operation);
if (strategy == null) {
throw new IllegalArgumentException("Unsupported operation: " + operation);
}
return strategy.calculate(a, b);
}
}
4)客户端测试
a、基础用法(直接使用策略)
public class Main {
public static void main(String[] args) {
int a = 10, b = 5;
System.out.println(new AddStrategy().calculate(a, b));
System.out.println(new SubStrategy().calculate(a, b));
System.out.println(new MulStrategy().calculate(a, b));
}
}
b、推荐用法(通过 Context)
优势体现:
- 客户端无需
new具体策略类; - 策略可通过配置、枚举或工厂动态加载。
public class MainWithContext {
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println(calc.execute("add", 10, 5)); // a + b = 15
System.out.println(calc.execute("sub", 10, 5)); // a - b = 5
System.out.println(calc.execute("mul", 10, 5)); // a * b = 50
}
}
输出:
a + b = 15
a - b = 5
a * b = 50
4、 FAQ
1)优点
- 算法可自由切换:运行时动态选择;
- 避免条件分支:消除
if-else/switch,提升可读性; - 扩展性强:新增策略只需实现接口;
- 符合开闭原则:对扩展开放,对修改关闭。
2)注意事项
- 类数量增加:每个策略对应一个类(若策略简单,可考虑 Lambda 表达式简化);
- 客户端需知道所有策略(除非使用 Context 封装);
- 策略间无法共享状态(若需状态,考虑结合状态模式)。


