当前位置: 首页 > news >正文

策略模式精讲+实战

策略模式(Strategy Pattern)精讲 —— 结合 Spring 实战

1. 官方标准定义(GoF 原话)

定义一组算法,将每个算法都封装起来,并且使它们之间可以互相替换。该模式让算法的变化独立于使用算法的客户端(调用方)。核心原则:针对接口编程,而不是针对实现编程。策略模式(Strategy Pattern)是 GoF 23 种设计模式中的行为型模式。

2. 一句话"人话"解读

它是一个策略路由器。你只需要告诉上下文(Context)你想要什么"策略标识"(比如"ALIPAY"),它就会自动把对应的"技能/算法"(比如支付宝支付逻辑)拿出来执行,而调用方完全不用关心底层是怎么if-else判断类型的。

3. 模式的核心三要素(结构定义)

为满足上面的定义,模式必须包含以下 3 个角色:

角色职责对应代码
抽象策略(Strategy)定义一个公共接口,所有算法都遵循这个"合同"PaymentStrategy接口
具体策略(ConcreteStrategy)实现接口的具体类,封装了具体的业务算法AlipayStrategyWechatStrategy
上下文(Context)持有策略引用,负责根据条件路由到具体策略PaymentContext
设计原则
  • 封装变化:找出应用中可能需要变化的部分,把它们独立出来
  • 面向接口编程:策略的具体实现依赖接口,而不是依赖实现类
  • 组合优于继承:Context 通过组合持有一个 Strategy 引用,而不是继承具体策略
4. 为什么这个定义很重要?(结合 Spring 场景)
  • "互相替换":因为 Spring 把策略类注入了Map<String, Strategy>,只要type匹配,随时可以替换某个策略的实现类,调用方完全无感知。新增策略时,客户端代码完全不用改,完美符合"开闭原则"。
  • "变化独立于客户端":客户端(Controller)只需要传"WECHAT",不需要知道微信支付类是否被 AOP 代理了。无论注入的是原始类还是代理类,代码都能正常运行——这就是接口编程的威力。
5. 代码实战(解决支付场景)

假设有一个支付系统,支持支付宝、微信等多种渠道。我们将使用 Spring 的依赖注入特性来优雅实现。

5.1 原始反面案例(使用instanceof
// ❌ 反面教材:每当新增支付方式,都要修改此处代码,违反开闭原则 public String pay(Object channel) { if (channel instanceof Alipay) { // 支付宝逻辑 } else if (channel instanceof WechatPay) { // 微信逻辑 } throw new UnsupportedOperationException(); }
5.2 重构为策略模式(优雅实现)
第一步:定义策略接口
public interface PaymentStrategy { // 策略标识(用于前端传参,替代 instanceof 判断) String getType(); // 执行支付 void pay(Double amount); }
第二步:实现具体策略(交给 Spring 管理)
@Component public class AlipayStrategy implements PaymentStrategy { @Override public String getType() { return "ALIPAY"; } @Override public void pay(Double amount) { System.out.println("使用支付宝支付:" + amount); // 此处调用支付宝 SDK... } } @Component public class WechatStrategy implements PaymentStrategy { @Override public String getType() { return "WECHAT"; } @Override public void pay(Double amount) { System.out.println("使用微信支付:" + amount); // 此处调用微信 SDK... } }
第三步:创建策略上下文(核心工厂)

利用 Spring 的构造函数注入,将所有的策略List自动转换为Map<String, Strategy>此时已彻底消灭instanceof

@Component public class PaymentContext { private final Map<String, PaymentStrategy> strategyMap; @Autowired public PaymentContext(List<PaymentStrategy> strategies) { // 将 List 转为 Map,Key 为策略自定义的类型标识 this.strategyMap = strategies.stream() .collect(Collectors.toMap(PaymentStrategy::getType, Function.identity())); } // 对外统一调用接口 public void executePay(String type, Double amount) { PaymentStrategy strategy = strategyMap.get(type); if (strategy == null) { throw new IllegalArgumentException("不支持的支付方式: " + type); } strategy.pay(amount); } }
第四步:Controller 层调用
@RestController @RequestMapping("/api/pay") public class PayController { @Autowired private PaymentContext paymentContext; @PostMapping public String pay(@RequestParam String type, @RequestParam Double amount) { // 前端传入 "ALIPAY" 或 "WECHAT",无需任何类型判断 paymentContext.executePay(type, amount); return "支付成功"; } }
6. 策略模式 vsinstanceof的优势
对比维度if-else+instanceof策略模式(Map 路由)
开闭原则违反(新增渠道需修改原有类)符合(新增渠道只需新建类加@Component
代码可读性随着分支增多,逻辑臃肿难维护路由清晰,业务逻辑内聚在各自类中
测试难度需要 mock 大量无关分支可单独测试每个策略类
运行时性能链式判断,O(N) 复杂度Map 哈希查找,O(1) 复杂度
7. 联动避坑(Spring 代理问题)

如果具体策略类(如AlipayStrategy)本身被@Transactional@Cacheable注解,Spring 会为其生成代理对象。此时直接通过new创建实例会失去代理能力,必须通过 Spring 容器获取策略实例。这正是策略上下文(Context)通过依赖注入管理策略实例的重要原因。

http://www.jsqmd.com/news/1116030/

相关文章:

  • 当你的AI助手学会“暗语”:Claude Code 隐写标记事件深度解析
  • AD74413R与STM32F722VE的SPI通信与同步控制实现
  • 2026年10款精选论文降AI率软件实测:规范定稿实战对比实用指南
  • openEuler/llm_solution多模型支持:DeepSeek、Qwen、Llama等50+主流模型部署对比
  • 如何用League Akari打造你的英雄联盟终极自动化助手:完整指南
  • utsudo多架构支持:AMD64/ARM64/loongarch64部署最佳实践
  • PIC32MX675F512L驱动WS2812 LED的嵌入式开发实践
  • EulerPublisher容器镜像测试完全指南:shUnit2框架的实战应用
  • 炉石传说55项全能优化插件HsMod:终极游戏体验增强方案
  • C#调用YOLOv8实现工业视觉检测:.NET开发者的快速集成指南
  • 计算机毕业设计之黄海学院毕业生管理系统
  • ICM-42688-P与PIC18F4680在工业自动化中的高效组合
  • Android设备自动启动技术实现:Magisk Autoboot模块深度解析
  • STM32L031C6与AD74413R的SPI通信优化实践
  • 终极Markdown浏览器扩展:3分钟打造专业文档阅读体验
  • nestos-installer架构设计:模块化安装工具的实现原理
  • STM32外扩EEPROM存储方案与优化实践
  • 5分钟快速上手ncmdumpGUI:轻松转换网易云音乐NCM格式音频文件
  • 【Java毕业设计】动漫作品分享与论坛评论交流系统的设计与实现 在线漫画资源分享与爱好者交流平台(源码+文档+远程调试,全bao定制等)
  • 三步永久保存微信聊天记录:解密WeChatMsg数据自主新方案
  • DDrawCompat:让Windows 10/11完美运行经典DirectX游戏的终极解决方案
  • 终极窗口调整指南:3分钟学会Windows窗口强制大小调整
  • WarcraftHelper技术解析:魔兽争霸3现代化改造方案
  • utdnsmasq进阶:自定义配置与网络优化实践指南
  • KMX62 IMU与PIC32微控制器的平衡控制方案
  • BLDC电机FOC控制方案:从硬件设计到算法优化
  • 飞书文档转Markdown:告别复制粘贴,3分钟搞定文档迁移
  • STM32与EEPROM低功耗数据存储方案详解
  • BiSheng JDK 11深度解析:华为开源高性能Java运行时的终极指南
  • MVP到规模化:技术架构的演进路线图