news 2026/7/1 18:39:11

设计模式-策略模式精讲

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
设计模式-策略模式精讲

如下是本文目录:

1. 为什么需要策略模式

1.1 使用策略模式要解决的核心痛点

1.2 正确典型使用场景

1.3 不适合策略模式的场景

2. 五种常见实现方式

2.1 基础接口实现式(原生标准)

2.2 枚举策略式(极简无类爆炸)

2.3 工厂+策略整合式(解耦增强)

2.4 Lambda匿名策略式(轻量化极简)

2.5 Spring容器策略式(工程实战主流)

2.6 五种实现方式对比表

2.7 高级拓展:组合策略(多策略叠加执行)

2.8 拓展案例:文件加密策略

2.9 策略模式UML结构图

2.10 JDK标准库原生策略模式落地(面试高频)

2.11 相似设计模式核心区分表

3. 策略模式核心痛点与解决办法

3.1 策略类过多(类爆炸)

3.2 策略分发硬编码

3.3 空策略、未知策略容错

3.4 策略重复创建、性能冗余

4. 总结

1. 为什么需要策略模式

策略模式是行为型设计模式,核心目标:定义一系列独立的算法(业务策略),将每个算法封装为独立类,让算法可以互相替换,且算法的变化不会影响调用算法的客户端,完美实现业务算法与业务调用逻辑的解耦。

换句话讲策略模式就是把多变的业务算法单独封装成一个个可替换的独立类,外部调用代码只负责调度,不需要关心算法内部细节,换算法不用改主流程,实现算法和业务代码解绑。

1.1 使用策略模式要解决的核心痛点

a. 业务中大量分支判断(if-else/switch),随着策略增多,代码臃肿冗长、维护成本极高

b. 算法逻辑高度耦合在业务主类中,修改、新增算法需要改动核心业务代码,违反开闭原则

c. 不同业务算法逻辑混杂,代码可读性差,容易出现分支逻辑冲突修改牵一发而动全身的问题;

d. 算法无法独立复用、单独测试,多场景复用相同算法需要重复编码

1.2 正确典型使用场景

a.多条件分支业务计算:订单支付方式(微信/支付宝/银行卡)、折扣计算(满减/折扣/优惠券)、运费计算;

b.多类型数据处理策略:文件解析(Excel/Word/PDF)、消息推送(短信/邮件/APP推送)、日志输出(控制台/文件/数据库);

c.业务规则动态切换:会员等级权益计算、风控校验规则、排序筛选策略、汇率换算策略;

d.框架层级算法替换:线程池拒绝策略、Spring资源加载策略、序列化策略、缓存淘汰策略。

1.3 不适合策略模式的场景

a.策略极少变动、分支固定仅1-2个固定分支,业务终身不会新增策略,使用if-else更简洁

b.算法逻辑极其简单单句代码即可实现的分支逻辑,拆分策略类会造成类爆炸、过度设计;

c.策略之间存在强依赖、无法独立拆分:多个算法逻辑耦合绑定,拆分后会增加代码复杂度

d.临时一次性业务策略无需复用、无需扩展的临时分支逻辑,无需封装策略。

2. 五种常见实现方式

策略模式三大标准核心角色

a.Strategy(策略接口)定义所有算法统一公共规范,对外暴露统一执行方法;

b.ConcreteStrategy(具体策略实现类)独立实现接口,封装单一算法逻辑,单一职责;

c.Context(上下文调度类)持有策略对象引用,提供动态修改策略入口,接收客户端请求并委托策略执行。

2.1 基础接口实现式(原生标准)

特点:定义统一策略接口不同策略实现接口上下文类持有策略对象,对外提供统一调用入口,是最经典、最标准的策略模式实现。

// 1. 统一策略接口(定义算法规范) public interface DiscountStrategy { // 计算折扣后价格 BigDecimal calculatePrice(BigDecimal originalPrice); } // 2. 具体策略实现1:无优惠 public class NoDiscountStrategy implements DiscountStrategy { @Override public BigDecimal calculatePrice(BigDecimal originalPrice) { return originalPrice; } } // 3. 具体策略实现2:八折优惠 public class EightDiscountStrategy implements DiscountStrategy { @Override public BigDecimal calculatePrice(BigDecimal originalPrice) { return originalPrice.multiply(new BigDecimal("0.8")); } } // 4. 具体策略实现3:满减优惠 public class FullReductionStrategy implements DiscountStrategy { @Override public BigDecimal calculatePrice(BigDecimal originalPrice) { // 满100减20 return originalPrice.compareTo(new BigDecimal("100")) >= 0 ? originalPrice.subtract(new BigDecimal("20")) : originalPrice; } } // 5. 上下文类(统一调度入口,持有策略) public class DiscountContext { // 持有策略接口引用,运行时通过传入不同实现类来切换优惠算法 (这也是JAVA中多态的核心运用) private DiscountStrategy discountStrategy; // 注入策略 public DiscountContext(DiscountStrategy discountStrategy) { this.discountStrategy = discountStrategy; } // 动态修改策略 public void setDiscountStrategy(DiscountStrategy discountStrategy) { this.discountStrategy = discountStrategy; } // 对外统一调用方法 public BigDecimal executeCalculate(BigDecimal originalPrice) { return discountStrategy.calculatePrice(originalPrice); } } // 测试使用 public class StrategyTest { public static void main(String[] args) { DiscountContext context = new DiscountContext(new EightDiscountStrategy()); System.out.println("八折后价格:" + context.executeCalculate(new BigDecimal("200"))); // 动态切换策略 context.setDiscountStrategy(new FullReductionStrategy()); System.out.println("满减后价格:" + context.executeCalculate(new BigDecimal("200"))); } }

适用场景:策略数量适中、需要动态切换策略、常规业务解耦场景,是企业开发通用首选。

优缺点:结构清晰、完全符合开闭原则、策略可独立扩展;缺点是策略较多时会产生大量独立策略类。

2.2 枚举策略式(极简无类爆炸)

特点:将所有策略封装在枚举内部,通过枚举常量区分不同策略,整合策略定义、实现、分发,无需创建大量独立实现类,代码极简。

// 枚举策略:整合所有折扣算法 public enum DiscountEnumStrategy { // 枚举常量:对应不同策略 NO_DISCOUNT(1, "无优惠") { @Override public BigDecimal calculatePrice(BigDecimal originalPrice) { return originalPrice; } }, EIGHT_DISCOUNT(2, "八折优惠") { @Override public BigDecimal calculatePrice(BigDecimal originalPrice) { return originalPrice.multiply(new BigDecimal("0.8")); } }, FULL_REDUCTION(3, "满减优惠") { @Override public BigDecimal calculatePrice(BigDecimal originalPrice) { return originalPrice.compareTo(new BigDecimal("100")) >= 0 ? originalPrice.subtract(new BigDecimal("20")) : originalPrice; } }; // 策略编码、描述 private final int code; private final String desc; DiscountEnumStrategy(int code, String desc) { this.code = code; this.desc = desc; } // 抽象策略方法,由每个枚举常量实现 public abstract BigDecimal calculatePrice(BigDecimal originalPrice); // 根据code获取对应策略 public static DiscountEnumStrategy getStrategyByCode(int code) { for (DiscountEnumStrategy strategy : values()) { if (strategy.code == code) { return strategy; } } throw new IllegalArgumentException("无效的优惠策略编码"); } // getter方法 public int getCode() { return code; } public String getDesc() { return desc; } } // 测试使用 public class EnumStrategyTest { public static void main(String[] args) { // 根据编码获取策略并执行 DiscountEnumStrategy strategy = DiscountEnumStrategy.getStrategyByCode(2); System.out.println(strategy.getDesc() + "价格:" + strategy.calculatePrice(new BigDecimal("200"))); } }

适用场景:策略固定、不会频繁新增,策略数量可控的业务场景,替代大量简单策略类。

优缺点:杜绝类爆炸、代码集中统一管理、调用简洁;缺点是策略逻辑复杂时,枚举类会过于臃肿,不适合复杂算法。

2.3 工厂+策略整合式(解耦增强)

特点:结合简单工厂模式,新增策略工厂类统一创建、分发策略对象,彻底屏蔽策略创建细节,客户端无需感知具体策略实现类,进一步解耦。

// 1. 策略接口(同基础实现) public interface DiscountStrategy { BigDecimal calculatePrice(BigDecimal originalPrice); } // 2. 具体策略实现 public class NoDiscountStrategy implements DiscountStrategy { @Override public BigDecimal calculatePrice(BigDecimal originalPrice) { return originalPrice; } } public class EightDiscountStrategy implements DiscountStrategy { @Override public BigDecimal calculatePrice(BigDecimal originalPrice) { return originalPrice.multiply(new BigDecimal("0.8")); } } // 3. 策略工厂类:统一生产策略 public class StrategyFactory { // 缓存所有策略,避免重复创建 private static final Map<String, DiscountStrategy> STRATEGY_CACHE = new HashMap<>(); // 静态初始化所有策略 static { STRATEGY_CACHE.put("noDiscount", new NoDiscountStrategy()); STRATEGY_CACHE.put("eightDiscount", new EightDiscountStrategy()); } // 根据key获取策略 public static DiscountStrategy getStrategy(String strategyKey) { DiscountStrategy strategy = STRATEGY_CACHE.get(strategyKey); if (strategy == null) { throw new IllegalArgumentException("不存在该优惠策略"); } return strategy; } } // 4. 上下文调用 public class FactoryStrategyContext { public BigDecimal executePrice(String strategyKey, BigDecimal originalPrice) { // 工厂获取策略,直接执行 DiscountStrategy strategy = StrategyFactory.getStrategy(strategyKey); return strategy.calculatePrice(originalPrice); } } // 测试使用 public class FactoryStrategyTest { public static void main(String[] args) { FactoryStrategyContext context = new FactoryStrategyContext(); BigDecimal result = context.executePrice("eightDiscount", new BigDecimal("200")); System.out.println("优惠后价格:" + result); } }

适用场景:策略数量多、需要统一管理策略实例、客户端无需感知策略细节的中大型业务场景。

优缺点:职责拆分更清晰、屏蔽创建细节、支持策略缓存复用;缺点是多了工厂类,小幅增加代码量。

2.4 Lambda匿名策略式(轻量化极简)

特点:基于Java8函数式接口特性,无需定义策略实现类,通过Lambda表达式动态实现策略逻辑,适合简单、临时性策略

// 1. 函数式策略接口(必须仅有一个抽象方法) @FunctionalInterface public interface DiscountStrategy { BigDecimal calculatePrice(BigDecimal originalPrice); } // 2. 上下文类 public class LambdaStrategyContext { private DiscountStrategy discountStrategy; public void setDiscountStrategy(DiscountStrategy discountStrategy) { this.discountStrategy = discountStrategy; } public BigDecimal executeCalculate(BigDecimal originalPrice) { return discountStrategy.calculatePrice(originalPrice); } } // 测试使用:Lambda动态传入策略,无需定义实现类 public class LambdaStrategyTest { public static void main(String[] args) { LambdaStrategyContext context = new LambdaStrategyContext(); // 无优惠策略 context.setDiscountStrategy(price -> price); System.out.println("无优惠价格:" + context.executeCalculate(new BigDecimal("200"))); // 八折策略 context.setDiscountStrategy(price -> price.multiply(new BigDecimal("0.8"))); System.out.println("八折价格:" + context.executeCalculate(new BigDecimal("200"))); // 满减策略 context.setDiscountStrategy(price -> price.compareTo(new BigDecimal("100")) >= 0 ? price.subtract(new BigDecimal("20")) : price); System.out.println("满减价格:" + context.executeCalculate(new BigDecimal("200"))); } }

适用场景:策略逻辑简单、临时动态定义、无需复用策略的场景,快速简化分支代码。

优缺点:极致精简、无需创建大量实现类、灵活度高;缺点是复杂策略逻辑会导致代码臃肿,无法单独复用和单元测试。

2.5 Spring容器策略式(工程实战主流)

特点:基于Spring IoC容器,将所有策略实现类交给Spring管理,通过依赖注入、Map自动注入批量获取所有策略,实现自动分发,是实际项目中最常用的实现方式。

// 1. 策略接口 public interface PayStrategy { // 支付方法 String pay(BigDecimal money); } // 2. 具体策略实现(交给Spring管理) @Component("wechatPay") public class WechatPayStrategy implements PayStrategy { @Override public String pay(BigDecimal money) { return "微信支付成功,支付金额:" + money; } } @Component("aliPay") public class AliPayStrategy implements PayStrategy { @Override public String pay(BigDecimal money) { return "支付宝支付成功,支付金额:" + money; } } @Component("bankPay") public class BankPayStrategy implements PayStrategy { @Override public String pay(BigDecimal money) { return "银行卡支付成功,支付金额:" + money; } } // 3. 策略上下文/调度器:Spring自动注入所有策略 @Component public class PayStrategyContext { // 自动注入所有PayStrategy实现类,key为组件名称,value为策略实例 @Autowired private Map<String, PayStrategy> payStrategyMap; // 根据支付类型获取策略并执行 public String executePay(String payType, BigDecimal money) { PayStrategy strategy = payStrategyMap.get(payType); if (strategy == null) { throw new IllegalArgumentException("不支持的支付方式"); } return strategy.pay(money); } } // 测试(Spring环境) @SpringBootTest public class SpringStrategyTest { @Autowired private PayStrategyContext payStrategyContext; @Test public void testPay() { System.out.println(payStrategyContext.executePay("wechatPay", new BigDecimal("99.9"))); System.out.println(payStrategyContext.executePay("aliPay", new BigDecimal("199.9"))); } }

适用场景:SpringBoot/Spring工程、企业级业务开发、需要频繁扩展策略、需要统一管理策略实例的场景。

优缺点:无需手动创建管理策略、新增策略只需新增实现类即可(完全开闭)、适配业务迭代;缺点是依赖Spring容器,非原生Java实现。

2.6 五种实现方式对比表

实现方式

开闭扩展性

是否类爆炸

代码简洁度

依赖环境

适用场景

基础接口实现式

优秀

中等

原生Java

通用业务、需要动态切换策略

枚举策略式

一般

原生Java

策略固定、数量少、无需频繁扩展

工厂+策略整合式

优秀

中等

原生Java

多策略统一管理、屏蔽创建细节

Lambda匿名策略式

极高

JDK8+

简单临时策略、快速简化分支代码

Spring容器策略式

极佳

可控

Spring环境

企业级项目、长期迭代扩展业务

注:类爆炸问题可通过分包管理(strategy/impl)优化;Spring策略式虽有多个实现类,但符合业务分层规范,是工程中最优解;简单场景无需过度封装,优先选择轻量化实现。

2.7 高级拓展:组合策略(多策略叠加执行)

业务中常需要多个策略叠加生效(满减后再打折),通过组合类统一串联执行所有策略

// 策略组合器 public class CombinedDiscountStrategy implements DiscountStrategy { private final List<DiscountStrategy> strategies; public CombinedDiscountStrategy(DiscountStrategy... strategies) { this.strategies = Arrays.asList(strategies); } @Override public double applyDiscount(double originalPrice) { double currentPrice = originalPrice; //模拟写法,生产上肯定会有更复杂的组合关系 for (DiscountStrategy strategy : strategies) { currentPrice = strategy.applyDiscount(currentPrice); } return currentPrice; } } // 使用:满300减50,再9折 DiscountStrategy combined = new CombinedDiscountStrategy( new FullReductionStrategy(300, 50), new PercentageDiscountStrategy(0.1) );

2.8 拓展案例:文件加密策略

// 策略接口 public interface EncryptionStrategy { String encrypt(String content); String decrypt(String encryptedContent); } // AES加密策略 public class AesEncryptionStrategy implements EncryptionStrategy {} // RSA加密策略 public class RsaEncryptionStrategy implements EncryptionStrategy {} // 上下文 public class FileEncryptor { private EncryptionStrategy strategy; public FileEncryptor(EncryptionStrategy strategy) { this.strategy = strategy; } public void encryptFile(String inputPath, String outputPath) { String content = readFile(inputPath); String encrypted = strategy.encrypt(content); writeFile(outputPath, encrypted); } }

2.9 策略模式UML结构图

_________________________ | Strategy | |------------------------| | + executeAlgorithm() | |________________________| ▲ ____________|_____________ | | | ______▼______ ____▼______ _____▼______ | Concrete | | Concrete | | Concrete | | StrategyA | | StrategyB | | StrategyC | |___________| |___________| |___________| ▲ | _____▼_____ | Context | |-----------| | - strategy| |___________|

2.10 JDK标准库原生策略模式落地(面试高频)

Comparator比较器:

List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5); Collections.sort(numbers, Comparator.naturalOrder()); // 升序策略 Collections.sort(numbers, Comparator.reverseOrder()); // 降序策略

ThreadPoolExecutor线程池拒绝策略:

ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 4, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10), new ThreadPoolExecutor.AbortPolicy() // 可切换Discard/CallerRuns等策略 );

2.11 相似设计模式核心区分表

模式核心区别
工厂模式关注对象创建策略模式关注算法行为选择与替换
命令模式封装单次操作请求,支持撤销、排队策略模式封装可复用完整算法
状态模式内部状态自动流转切换策略模式需要客户端显式指定切换算法

3. 策略模式核心痛点与解决办法

3.1 策略类过多(类爆炸)

问题描述:业务策略繁多时,基础实现式会产生大量策略实现类项目结构臃肿,不利于管理

解决方案

1.简单固定策略:使用枚举策略式统一收拢所有策略,无需拆分独立类;

2.简单动态策略:使用Lambda表达式动态定义,省去实现类;

3.复杂多策略:通过分包管理,将策略实现类统一放入strategy/impl包,规范项目结构。

3.2 策略分发硬编码

问题描述:传统写法中,客户端通过硬编码key、分支判断获取策略,新增策略需要修改分发代码,违反开闭原则。

解决方案

1.原生场景:使用工厂模式+缓存Map统一分发,无需修改核心代码;

2.Spring场景:利用Spring自动注入Map,新增策略只需新增实现类,自动注册生效;

3.统一策略编码规范:通过配置文件、枚举映射策略key,彻底消除硬编码。

3.3 空策略、未知策略容错

问题描述:传入不存在的策略key,会出现空指针、未知异常,程序健壮性差。

解决方案

1. 策略获取时增加非空判断,兜底返回默认策略;

2.自定义业务异常,替换原生空指针异常,统一异常提示;

3. 枚举策略通过code遍历匹配,无匹配时抛出明确异常。

3.4 策略重复创建、性能冗余

问题描述:每次调用策略都新建对象,频繁调用会产生大量临时对象,造成GC压力。

解决方案

1. 原生场景:通过静态Map缓存所有策略实例,全局复用;

2. Spring场景:利用Spring单例特性,策略类默认单例托管,无需手动缓存;

3. 无状态策略天然可复用,禁止每次调用new新对象。

4. 总结

策略模式的核心是解耦分支算法、拥抱开闭原则、实现算法可替换规避臃肿的if-else代码,选择实现方式需结合业务场景:

1.企业Spring项目首选Spring容器策略式:扩展性最强、适配业务迭代、无需手动管理实例;

2.固定少量策略选枚举式:代码简洁、无类爆炸、统一管理;

3.简单临时策略选Lambda式:极致精简,快速优化分支代码;

4.原生Java通用场景选基础/工厂策略式:结构标准、通用性强;

5.坚决避免过度设计:少量固定分支、无扩展需求的场景,无需强行使用策略模式。

理解策略模式的核心思想而非死记代码,才能在复杂业务中彻底消灭分支嵌套,写出高扩展、高维护、高复用的业务代码

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/1 18:32:56

从内层到后道——PCB全制程收放板方案的系统性规划

背景一条PCB产线从内层制作到成品出货&#xff0c;经过数十道工序。每道工序之间的板件流转&#xff0c;都依赖收放板机完成。产线规划时如果逐工序单独选型&#xff0c;容易出现设备型号杂乱、备件不统一、数据接口不匹配等问题。将收放板设备作为整体进行系统性规划&#xff…

作者头像 李华
网站建设 2026/7/1 18:32:25

三轴太阳花技术解析:追光原理、折叠机制与系统架构

摘要三轴太阳花&#xff08;三轴追踪式光伏向日葵&#xff09;是一种集太阳追踪、花瓣折叠、发电逆变储能于一体的景观化光伏发电装置。本文从机械结构、控制算法、折叠机制、电气系统四个维度进行技术解析&#xff0c;并与双轴追踪系统进行对比。一、太阳追踪的机械与控制原理…

作者头像 李华
网站建设 2026/7/1 18:23:18

Codex与 Claude Code安装与配置流程

本文整合 Codex 与 Claude Code 两款主流 AI 编程助手的安装与配置流程&#xff0c;覆盖 Windows、macOS、Linux 三大系统&#xff0c;所有命令均经过验证&#xff0c;可直接复制使用。 目录 一、环境准备二、Codex 安装与配置三、Claude Code 安装与配置四、常见问题排查 一、…

作者头像 李华
网站建设 2026/7/1 18:21:35

使用JMeter进行gRPC微服务性能测试的完整指南

1. 项目概述&#xff1a;为什么需要gRPC性能测试&#xff1f; 在微服务架构成为主流的今天&#xff0c;服务间的通信方式直接决定了系统的整体性能和稳定性。传统的RESTful API基于HTTP/1.1&#xff0c;其文本传输、请求-响应模式在需要高吞吐、低延迟的内部服务调用场景下&am…

作者头像 李华
网站建设 2026/7/1 18:21:03

从XXE漏洞原理到实战:以CTF为例解析XML外部实体注入与防御

1. 项目概述&#xff1a;从一道CTF题看XXE漏洞的实战价值最近在复盘GHCTF的一道WEB题目“EZ ReadFile”时&#xff0c;我再次深刻体会到XML外部实体注入&#xff08;XXE&#xff09;漏洞在实战中的威力。这道题本身并不复杂&#xff0c;但它完美地展示了XXE如何从一个看似无害的…

作者头像 李华
网站建设 2026/7/1 18:20:09

免费获取百度文库文档的终极指南:开源工具帮你突破下载限制

免费获取百度文库文档的终极指南&#xff1a;开源工具帮你突破下载限制 【免费下载链接】baidu-wenku fetch the document for free 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wenku 你是否曾经在百度文库找到一份急需的学习资料或工作报告&#xff0c;却因为…

作者头像 李华