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

【西瓜带你学设计模式 | 第十五期 - 策略模式】策略模式 —— 算法封装与动态替换实现、优缺点与适用场景

文章目录

    • 前言
    • 1. 策略模式是什么?
    • 2. 策略模式解决什么问题?
    • 3. 核心结构
      • 3.1 Strategy(抽象策略)
      • 3.2 ConcreteStrategy(具体策略)
      • 3.3 Context(上下文)
    • 4. 实现思路
    • 5. 示例
      • 5.1 Strategy:抽象策略
      • 5.2 ConcreteStrategy:具体策略
        • 5.2.1 满减策略
        • 5.2.2 会员折扣策略
        • 5.2.3 阶梯价策略
      • 5.3 Context:上下文
      • 5.4 Client:客户端选择策略并调用
    • 6. 优缺点
      • 6.1 优点
      • 6.2 缺点
    • 7. 和其他模式怎么区分?
      • 7.1 策略 vs 简单工厂/工厂方法
      • 7.2 策略 vs 模板方法
      • 7.3 策略 vs 状态模式
    • 8. 适用场景
    • 9. 总结

前言

在很多业务系统里,我们经常会遇到“同一类事情,不同情况下用不同算法/规则”的需求,比如:

  • 支付方式不同(支付宝/微信/银行卡/积分)
  • 价格计算不同(满减、折扣、阶梯价、会员价)
  • 消息发送不同(短信/邮件/推送)
  • 文件处理不同(压缩算法/加密算法/校验算法)

这些场景通常有一个共同点:算法会变,但调用方希望保持稳定
策略模式(Strategy Pattern)要解决的核心就是:

把算法/规则从使用它的代码中剥离出来,让它们以“可替换”的方式独立变化;客户端只依赖统一的抽象接口。


1. 策略模式是什么?

策略模式是一种行为型设计模式,通过“封装一组可复用的算法”,并让它们都实现同一个接口,从而做到:

  • 客户端根据条件选择合适的策略
  • 后续新增/修改策略时,不需要改动客户端的大结构(遵循开闭原则)

2. 策略模式解决什么问题?

  1. 同一业务流程里会出现多个分支(if/else 很多)
  2. 算法(或规则)经常变化,且变化频率高
  3. 不希望改动调用方逻辑,只希望替换不同实现
  4. 希望代码结构更清晰、可扩展

如果代码里出现“根据类型/条件选择不同计算方式”的分支,而且会不断增多,就很适合策略模式。


3. 核心结构

3.1 Strategy(抽象策略)

定义策略必须实现的方法,例如calculatePrice(...)

3.2 ConcreteStrategy(具体策略)

多个具体类实现同一接口,对应不同算法或规则。

3.3 Context(上下文)

上下文类持有Strategy,负责“在合适时机调用策略”。


4. 实现思路

按你给的享元模式示例那种“拆角色 + 实现 + 示例”的思路,策略模式通常是:

  1. 定义Strategy接口(统一方法签名)
  2. 写多个ConcreteStrategy(不同算法)
  3. Context,构造时注入策略,或运行时切换
  4. 客户端只跟ContextStrategy交互,不关心具体算法细节

5. 示例

不同规则计算价格

5.1 Strategy:抽象策略

publicinterfacePricingStrategy{doublecalculate(doubleoriginalPrice);}

5.2 ConcreteStrategy:具体策略

5.2.1 满减策略
publicclassDiscountByCouponStrategyimplementsPricingStrategy{@Overridepublicdoublecalculate(doubleoriginalPrice){// 假设满100减20if(originalPrice>=100){returnoriginalPrice-20;}returnoriginalPrice;}}
5.2.2 会员折扣策略
publicclassMemberDiscountStrategyimplementsPricingStrategy{@Overridepublicdoublecalculate(doubleoriginalPrice){// 会员9折returnoriginalPrice*0.9;}}
5.2.3 阶梯价策略
publicclassTieredPricingStrategyimplementsPricingStrategy{@Overridepublicdoublecalculate(doubleoriginalPrice){// 假设阶梯:>=200打8折,>=100打9折,否则原价if(originalPrice>=200)returnoriginalPrice*0.8;if(originalPrice>=100)returnoriginalPrice*0.9;returnoriginalPrice;}}

5.3 Context:上下文

publicclassShoppingCart{privatefinalPricingStrategystrategy;publicShoppingCart(PricingStrategystrategy){this.strategy=strategy;}publicdoublecheckout(doubleoriginalPrice){returnstrategy.calculate(originalPrice);}}

5.4 Client:客户端选择策略并调用

publicclassClient{publicstaticvoidmain(String[]args){doubleprice=150;ShoppingCartcart1=newShoppingCart(newDiscountByCouponStrategy());System.out.println("券后价格: "+cart1.checkout(price));ShoppingCartcart2=newShoppingCart(newMemberDiscountStrategy());System.out.println("会员价: "+cart2.checkout(price));ShoppingCartcart3=newShoppingCart(newTieredPricingStrategy());System.out.println("阶梯价: "+cart3.checkout(price));}}

会发现:

  • “选择哪种计算方式”的逻辑被独立出来了(策略类)
  • ShoppingCart不关心具体算法,只负责调用策略
  • 将来新增“新计算规则”,只要新增一个策略类即可

6. 优缺点

6.1 优点

  1. 消除大量 if/else(条件分支被策略类替代)
  2. 算法可扩展:新增策略不必大改原代码
  3. 复用性强:策略实现可以在多个上下文中使用
  4. 更符合开闭原则:对扩展开放,对修改关闭

6.2 缺点

  1. 策略类增多:可能导致类数量上升
  2. 客户端/工厂需要维护“策略选择逻辑”(如果选择逻辑仍写一堆 if,可能又回来了)
  3. 如果策略之间共享复杂公共逻辑,可能需要进一步抽象(或结合模板方法/组合等)

7. 和其他模式怎么区分?

7.1 策略 vs 简单工厂/工厂方法

  • 策略:解决“算法/规则如何替换”
  • 工厂:解决“对象如何创建(选择具体策略类)”

实际项目里经常组合使用:工厂负责创建对应策略,策略负责算法本体。

7.2 策略 vs 模板方法

  • 模板方法:把“流程骨架”固定,把某些步骤延迟到子类实现
  • 策略:把“某个可变点”直接封装为独立算法,运行时可切换

7.3 策略 vs 状态模式

  • 状态模式:对象在不同状态下行为不同,且状态通常会在运行过程中自动切换
  • 策略模式:通常由外部决定当前使用哪种策略(策略本身不一定管理“状态流转”)

8. 适用场景

满足以下情况时,策略模式很合适:

  • 系统需要在多种算法/规则之间切换
  • 算法实现彼此差异较大,但对外暴露统一接口
  • 频繁出现“if/else 根据条件选择不同处理”
  • 希望将算法从业务流程中解耦,便于扩展与测试

9. 总结

策略模式通过“抽象策略 + 多个具体策略 + 上下文持有策略引用”,把可变算法/规则从调用方逻辑中解耦出来。客户端只需选择合适的策略即可完成行为替换,从而减少分支代码、提高扩展性。

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

相关文章:

  • Sonic云真机平台结果分析与报告:可视化测试数据展示方案
  • app抓包 | 木木模拟器 + Burp Suite 系统代理抓包
  • OpenClaw自动化测试:Qwen3-14b_int4_awq在开发提效中的应用
  • 厂房防水补漏公司选购,广州久鼎建设工程值得考虑吗 - mypinpai
  • 望获官网上线代码实时性AI优化服务,欢迎免费使用
  • Python入门项目首选:打造个人卡证信息管理小工具
  • 增量式编码器ABZ信号解析:从示波器波形到实际应用调试技巧
  • Topit:重新定义macOS窗口管理,让多任务处理效率倍增
  • ANSYS Maxwell 3D线圈磁场仿真:从模型分割到结果解析全流程
  • 从冠军到“沪上第一胖“:运动员退役后体重暴涨523斤的健康警示
  • Limine协议参考实现:标准引导接口的设计理念与实现细节
  • 工厂模式、代理模式与单例模式的介绍
  • 苏州禾艺居装饰口碑如何,在平望地区性价比高不高? - 工业品牌热点
  • 如何将图像转换为3D模型?创意实体化的零代码解决方案
  • BOTW Save Editor GUI使用指南
  • 暗黑3技能连点器完整使用指南:从零开始到精通操作
  • 屋顶光伏发电施工团队怎么选,北京东胜华宸科技好用吗? - 工业品网
  • QT:基于TCP的Socket通讯实战指南
  • Filament Shield 生产环境部署指南:从开发到上线的完整流程
  • 从零到一:基于STM32与ThingsCloud的智能设备快速接入实战
  • 高斯数据库(GaussDB)SQL 常用语句总结
  • 太原家用净水器直销厂家推荐,2026优质分析揭晓,家用净水设备/直饮净水系统/商用直饮机,家用净水器公司口碑推荐 - 品牌推荐师
  • TensorFlow Lite Micro优化技巧:10个方法让你的模型运行更快更省电
  • Windows 10/11轻松解除磁盘写保护教程
  • 从 88.3% 到 9.88%!Paperxie 降 AIGC 率:毕业论文 AI 痕迹「清零神器」
  • 2026年福建省有实力的厂房防水补漏机构排名,性价比之选大揭秘 - 工业设备
  • Python并发范式革命(GIL已死,无锁当立):从threading到memoryview原子操作的全栈迁移指南
  • 告别手动翻页!用幻影联动+DLL调用,5分钟搞定通达信分时指标自动选股
  • 【EI复现】考虑网络动态重构的分布式电源选址定容优化方法(Matlab代码实现)
  • 2026深度分析罗兰艺境电子信息GEO技术案例,测评上海B2B制造企业优化过程与效果验证 - 罗兰艺境GEO