设计模式实战篇(二):业务逻辑“随时切换招式”——策略模式(Strategy Pattern)解析

是否正苦恼于一堆 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);

真正做到 零侵入可扩展插件化

相关推荐
小二·5 小时前
设计模式面试题(14道含答案)
设计模式
老鼠只爱大米11 小时前
Java 设计模式之适配器模式:系统集成的万能接口
java·设计模式·适配器模式·adapter·java设计模式
o0向阳而生0o16 小时前
112、23种设计模式之命令模式(20/23)
设计模式·命令模式
将编程培养成爱好17 小时前
C++ 设计模式《外卖骑手状态系统》
c++·ui·设计模式·状态模式
猿太极17 小时前
设计模式学习(3)-行为型模式
c++·设计模式
快乐非自愿19 小时前
常用设计模式:工厂方法模式
javascript·设计模式·工厂方法模式
guangzan1 天前
常用设计模式:模板方法模式
设计模式
Lei_3359671 天前
[設計模式]二十三種設計模式
设计模式
吃饺子不吃馅1 天前
面试官:JWT、Cookie、Session、Token有什么区别?
前端·设计模式·面试