找回密码
立即注册
搜索
发回帖 发新帖

5173

积分

0

好友

663

主题
发表于 2 小时前 | 查看: 4| 回复: 0

1. 定义

策略模式(Strategy Pattern):定义一系列算法,把每一个算法封装起来,并且让它们可以互相替换。算法的变化不会影响到使用算法的客户端。它属于行为型设计模式。

核心思想:把可变的算法 / 行为抽离,和上下文解耦;面向接口,而不是面向实现。

一句话:同一个动作有多种不同实现,随时切换,用策略模式。

2. 角色组成

  1. Strategy(策略接口):统一抽象方法,所有具体策略实现这个接口
  2. ConcreteStrategy(具体策略):不同的算法、实现逻辑
  3. Context(上下文):持有策略对象的引用,对外提供调用入口,负责和客户端交互

3. 代码示例(订单支付场景,高频例子)

// 1. 策略接口
public interface PayStrategy {
    void pay(Long orderId, BigDecimal money);
}

// 2. 具体策略:微信支付
public class WechatPayStrategy implements PayStrategy {
    @Override
    public void pay(Long orderId, BigDecimal money) {
        System.out.println("微信支付,订单:" + orderId + ",金额:" + money);
    }
}

// 支付宝支付
public class AlipayStrategy implements PayStrategy {
    @Override
    public void pay(Long orderId, BigDecimal money) {
        System.out.println("支付宝支付,订单:" + orderId + ",金额:" + money);
    }
}

// 银行卡支付
public class BankCardPayStrategy implements PayStrategy {
    @Override
    public void pay(Long orderId, BigDecimal money) {
        System.out.println("银行卡支付");
    }
}

// 3. 上下文 Context
public class PayContext {
    private PayStrategy strategy;

    // 注入策略
    public PayContext(PayStrategy strategy) {
        this.strategy = strategy;
    }

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

    public void executePay(Long orderId, BigDecimal money) {
        strategy.pay(orderId, money);
    }
}

// 客户端使用
public class Test {
    public static void main(String[] args) {
        PayContext context = new PayContext(new AlipayStrategy());
        context.executePay(1001L, new BigDecimal("99.00"));
        // 动态切换
        context.setStrategy(new WechatPayStrategy());
        context.executePay(1002L, new BigDecimal("199.00"));
    }
}

4. 工厂 + 策略(工程里最常用!面试加分)

上面写法客户端还要自己 new 策略,业务里一般用策略工厂,根据类型编码获取策略,消除大量 if-else:

@Component
public class PayStrategyFactory {
    private final Map<String, PayStrategy> strategyMap;

    // Spring自动注入所有实现类
    public PayStrategyFactory(List<PayStrategy> strategyList) {
        strategyMap = new HashMap<>();
        for (PayStrategy strategy : strategyList) {
            if (strategy instanceof WechatPayStrategy) {
                strategyMap.put("WECHAT", strategy);
            } else if (strategy instanceof AlipayStrategy) {
                strategyMap.put("ALIPAY", strategy);
            }
        }
    }

    public PayStrategy getStrategy(String payType) {
        PayStrategy strategy = strategyMap.get(payType);
        if (strategy == null) {
            throw new RuntimeException("不支持的支付方式");
        }
        return strategy;
    }
}

业务层直接根据 payType 从工厂拿策略,执行方法,完全消灭 if/else。

5. 适用场景

  1. 一个类有很多分支算法,大量 if-else / switch,后续还会新增分支(支付方式、运费计算、优惠规则、文件解析、排序算法)
  2. 需要动态切换算法
  3. 算法需要独立扩展、单独单元测试

常见例子:

  • 订单优惠策略:满减、折扣、优惠券、直减
  • 导出策略:Excel、PDF、CSV
  • 消息推送:短信、APP 推送、钉钉、邮件

6. 优缺点

✅ 优点

  1. 符合开闭原则:新增策略只需要新增实现类,不用修改原有代码
  2. 消除大量 if-else,代码清爽,可读性高
  3. 算法独立,方便单独测试、复用
  4. 动态切换策略

❌ 缺点

  1. 策略多的时候,类会变多,类爆炸
  2. 客户端需要知道有哪些策略,才能选择(工厂模式可以缓解这个问题)
  3. 策略之间如果有公共逻辑,不方便复用(可以抽抽象基类)

7. 和其他模式对比(高频追问)

策略模式 vs 状态模式

  • 策略:算法是平行、可互相替换,切换由客户端主动决定;策略之间无状态流转。比如支付方式,选微信还是支付宝,是主动选。
  • 状态模式:对象内部状态自动流转,状态切换是被动的,由对象内部驱动。订单:待支付→已支付→已发货,状态自动流转。

策略模式 vs 模板方法

  • 模板方法:固定流程骨架,部分步骤延迟子类实现(父类控制流程)
  • 策略模式:整套算法整体替换,没有固定流程骨架

8. Spring 中的策略模式落地

  • ResourceLoader,不同资源加载策略(文件、classpath、url)
  • Comparator(JDK 自带策略接口)
  • Converter 转换器
  • 各种 Handler、Processor 很多都是策略思想

✅ 精简口述版(面试背诵)

策略模式是行为型模式,定义一套统一策略接口,不同的算法封装成独立策略实现类,上下文持有策略引用,支持动态替换。主要用来消除 if else,满足开闭原则;新增算法只新增策略类,不改老代码。工程上一般配合工厂模式使用,根据编码匹配对应的策略。缺点是策略多了会类膨胀。它和状态模式容易混淆:策略是主动选择平行算法,状态是对象内部自动流转状态。

更多设计模式面试梳理与 Java 进阶实战内容,欢迎在云栈社区一起沉淀和讨论。




上一篇:Kimi额度烧太快?Anthropic:少开不必要的子Agent
下一篇:mKernel 跨节点 tile 级内核融合:Ring Attention 最高提速 1.88 倍
您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /1 下一条

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-28 02:41 , Processed in 0.071071 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表