是否正苦恼于一堆 if/else 引发的代码灾难?
想让算法像"武功招式"一样可随时切换?
策略模式就像"可拔插的算法模块",让你的代码像积木一样灵活。
策略模式就是专为这种"行为可替换"场景而设计的。
一、什么是策略模式?一句话讲透它的思想
策略模式是这样一种设计理念:
将一组可替代的算法独立封装,使调用者无需关注具体实现,并允许在运行时自由切换策略。
你可以把策略看成游戏中的"技能卡":
- 想打爆发,换"暴击卡"
- 想续航,换"回血卡"
- 想加速,换"疾风卡"
同样,在业务里也一样灵活。
⚙️ 二、策略模式适用的典型业务场景
| 业务领域 | 可切换的策略示例 | 说明 |
|---|---|---|
| 支付方式 | 支付宝、微信、银联 | 新增支付方式不影响旧代码 |
| 优惠算法 | 满减、折扣、积分换算 | 电商强需求 |
| 排序方案 | 时间、评分、热度排序 | 算法替换频繁 |
| 日志输出 | 本地、Kafka、ES | 运维系统常见 |
| 推荐系统 | 个性化、人气、新品 | 推荐算法可插拔 |
你会发现几乎所有"可替换业务逻辑"的地方都能用策略模式。
🧩 三、策略模式流程图
设置策略 客户端 Client Context 上下文 Strategy
策略接口 具体策略 A 具体策略 B
🧱 四、策略模式 UML 类图
<<interface>> Strategy +execute(double amount) AliPayStrategy +execute(double amount) WechatPayStrategy +execute(double amount) CreditCardStrategy +execute(double amount) PaymentContext -Strategy strategy +setStrategy(Strategy strategy) +pay(double amount)
🔄 五、策略模式时序图
User Context Strategy setStrategy() pay(amount) execute(amount) 返回结果 User Context Strategy
💻 六、策略模式 Java 实战:支付系统示例
1)策略接口
java
public interface PayStrategy {
void pay(double amount);
}
2)具体策略实现
java
public class AliPayStrategy implements PayStrategy {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付:" + amount + " 元");
}
}
public class WechatPayStrategy implements PayStrategy {
@Override
public void pay(double amount) {
System.out.println("使用微信支付:" + amount + " 元");
}
}
public class CreditCardStrategy implements PayStrategy {
@Override
public void pay(double amount) {
System.out.println("使用信用卡支付:" + amount + " 元");
}
}
3)Context(策略上下文)
java
public class PayContext {
private PayStrategy strategy;
public void setStrategy(PayStrategy strategy) {
this.strategy = strategy;
}
public void pay(double amount) {
strategy.pay(amount);
}
}
4)客户端调用
java
public class Main {
public static void main(String[] args) {
PayContext context = new PayContext();
context.setStrategy(new AliPayStrategy());
context.pay(100);
context.setStrategy(new WechatPayStrategy());
context.pay(200);
context.setStrategy(new CreditCardStrategy());
context.pay(300);
}
}
🚀 七、策略模式优势
| 特性 | 策略模式带来的能力 |
|---|---|
| 开闭原则 | 新策略无需改老代码 |
| 解耦 | 行为独立封装 |
| 插件化 | 可以动态组合策略 |
| 可测试性 | 每个策略单测方便 |
| 避免 if/else | 大幅提高可读性 |
如果你在项目中发现大量 if/else + 业务选择逻辑,大概率就是策略模式缺位了。
🧠 八、策略模式常见误区(反模式警示)
在实际项目中,很多开发者以为自己用了策略模式,但其实出现了以下"伪策略模式"问题:
❌ 误区一:策略内部出现 if/else 再分支
示例:
java
public class AliPayStrategy implements PayStrategy {
public void pay(double amount) {
if (isFastMode) { ... }
else if (isSafeMode) { ... }
}
}
这是典型的"策略里再塞策略",说明设计层级不清晰。
✔ 正确做法:
把内部行为继续分层,用"策略 + 工厂"组合拆分。
❌ 误区二:Context 写死策略创建逻辑
java
public PayContext() {
this.strategy = new AliPayStrategy();
}
这会让策略模式失去意义。
✔ 正确做法:
策略必须由外部注入,才能实现开闭原则。
❌ 误区三:策略太多、难以维护
当策略数量超过 20 个时,需要考虑:
- 把策略分包管理
- 考虑用枚举 + 工厂帮助组织
- 引入策略标签提升可读性
- 若策略本质是业务可配置逻辑 → 用"规则引擎"替代策略模式(如 drools)
🔍 九、策略模式与其他设计模式的对比(非常容易混淆)
| 模式 | 与策略模式的区别 |
|---|---|
| 模板方法(Template Method) | 父类定义流程,子类填步骤。策略模式是完全独立的算法替换。 |
| 状态模式(State) | 策略 = 动态切换行为;状态 = 动态切换对象状态,并影响下一个状态路径。 |
| 简单工厂 | 工厂解决"创建";策略解决"行为替换"。 |
| 责任链模式 | 策略只执行一个算法;责任链可以串多个算法。 |
一句话记忆:
模板方法是结构化流程;策略模式是横向替换算法;责任链模式是组合算法流程。
🏢 十、策略模式在企业级项目中的典型落地方式
1)在支付系统中
- 新增支付方式无需改旧代码
- 每个支付渠道对应独立策略
- 策略 + 工厂结合使用,与渠道编码映射
2)优惠模块(电商核心)
- 满减、满折、N 件 X 元
- 不同店铺可配置不同策略
- 支持按配置动态装配策略链(策略 + 责任链混合)
3)机器学习/推荐系统
- 替换排序算法
- 替换召回模型
- 替换归一化方法
策略模式让算法像插件一样"热插拔"。
🌱 十一、Spring 中的策略模式使用示例(非常实用)
Spring 对策略模式有天然支持。
方式一: 使用 @Autowired Map<String, Strategy>
java
@Autowired
private Map<String, PayStrategy> strategies;
Spring 会自动把所有实现该接口的 bean 装入 map,key 为 beanName。
java
strategies.get("aliPayStrategy").pay(100);
超级适合做"策略路由"。
方式二: 使用 @Qualifier 指定策略
java
@Autowired
@Qualifier("wechatPayStrategy")
private PayStrategy strategy;
方式三: 使用注解自动关联策略
自定义注解:
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PayChannel {
String value();
}
每个策略上使用:
java
@PayChannel("ALI")
public class AliPayStrategy implements PayStrategy {...}
启动扫描自动注册到策略池,非常企业级玩法。
⚡ 十二、策略模式自动注册 + 工厂增强版(高级示例)
1)策略工厂
java
public class StrategyFactory {
private static final Map<String, PayStrategy> STRATEGY_MAP = new HashMap<>();
public static void register(String key, PayStrategy strategy) {
STRATEGY_MAP.put(key, strategy);
}
public static PayStrategy get(String key) {
return STRATEGY_MAP.get(key);
}
}
2)策略自动注册
java
public abstract class AbstractPayStrategy implements PayStrategy {
protected AbstractPayStrategy(String key) {
StrategyFactory.register(key, this);
}
}
3)策略实现
java
public class AliPayStrategy extends AbstractPayStrategy {
public AliPayStrategy() {
super("ALI");
}
@Override
public void pay(double amount) {
System.out.println("支付宝支付:" + amount);
}
}
客户端即可:
java
StrategyFactory.get("ALI").pay(99.9);
真正做到 零侵入 、可扩展 、插件化。