设计模式实战篇(二):业务逻辑“随时切换招式”——策略模式(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);

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

相关推荐
高晶10 小时前
ARM 嵌入式 Linux 系统启动流程实战指南
设计模式·程序员
高晶10 小时前
BMS 通信开发实战:从 PMBus 协议到数据采集的完整指南
设计模式·程序员
geovindu10 小时前
rust:Memento Pattern(续)
开发语言·后端·设计模式·rust·行为模式·备忘录模
电子IT笔记10 小时前
老MES登录改造:弱密码和暴破一起治
设计模式
牧瀬クリスだ12 小时前
单例模式终极指南:从入门到防破坏
单例模式·设计模式
博风16 小时前
9、设计模式应用举例:责任链模式:计算阶乘
设计模式·责任链模式
电子IT笔记18 小时前
人走了,记录不能“空白”: MES×HR 离职人员下拉回显实战
设计模式
智慧城市203021 小时前
关键供应商连续交付不合格批次,说明质量风险可能持续存在。企业需要建立“批次隔离、加严检验、驻厂遏制、复检放行、供应商升级”的处置闭环,同时统筹保供。
数据分析·策略模式·战略咨询·流程管理
博风2 天前
8、设计模式应用举例:适配器模式:Iterator接口与Enumeration接口
设计模式·适配器模式
高晶2 天前
ARM 嵌入式 Linux 系统 U-Boot 开发与移植实战M
设计模式·程序员