1. 策略模式概述策略模式Strategy Pattern是一种行为型设计模式它定义了一系列算法并将每个算法封装起来使它们可以相互替换。这种模式让算法的变化独立于使用算法的客户端。在实际开发中我们经常会遇到需要根据不同条件执行不同算法的情况。比如电商系统中的折扣计算、支付系统的支付方式选择、游戏中的角色技能系统等。策略模式通过将算法封装成独立的策略类使得算法可以独立于客户端而变化。策略模式的核心思想将可变的部分算法/行为抽象出来封装成接口让客户端依赖于抽象而非具体实现。2. 策略模式的结构与实现2.1 UML类图解析策略模式的典型UML类图包含三个核心角色Context环境类持有一个策略类的引用负责调用具体策略Strategy抽象策略类定义所有支持的算法的公共接口ConcreteStrategy具体策略类实现Strategy接口的具体算法Context → Strategy Strategy ← ConcreteStrategyA Strategy ← ConcreteStrategyB2.2 代码实现示例下面是一个完整的Java实现示例// 抽象策略接口 public interface DiscountStrategy { double applyDiscount(double originalPrice); } // 具体策略类无折扣 public class NoDiscount implements DiscountStrategy { Override public double applyDiscount(double originalPrice) { return originalPrice; } } // 具体策略类固定折扣 public class FixedDiscount implements DiscountStrategy { private double discountAmount; public FixedDiscount(double discountAmount) { this.discountAmount discountAmount; } Override public double applyDiscount(double originalPrice) { return originalPrice - discountAmount; } } // 具体策略类百分比折扣 public class PercentageDiscount implements DiscountStrategy { private double percentage; public PercentageDiscount(double percentage) { this.percentage percentage; } Override public double applyDiscount(double originalPrice) { return originalPrice * (1 - percentage/100); } } // 环境类 public class DiscountContext { private DiscountStrategy strategy; public void setStrategy(DiscountStrategy strategy) { this.strategy strategy; } public double executeStrategy(double originalPrice) { return strategy.applyDiscount(originalPrice); } } // 客户端使用 public class Client { public static void main(String[] args) { DiscountContext context new DiscountContext(); // 使用无折扣策略 context.setStrategy(new NoDiscount()); System.out.println(Price after no discount: context.executeStrategy(100)); // 使用固定折扣策略 context.setStrategy(new FixedDiscount(20)); System.out.println(Price after fixed discount: context.executeStrategy(100)); // 使用百分比折扣策略 context.setStrategy(new PercentageDiscount(10)); System.out.println(Price after percentage discount: context.executeStrategy(100)); } }2.3 实现要点分析策略接口设计策略接口应该足够抽象能够涵盖所有可能的算法变体。接口方法命名要具有通用性如applyDiscount而不是calculatePercentageDiscount。上下文类设计通常通过构造函数或setter方法注入策略对象可以结合工厂模式来创建策略对象可以提供默认策略实现策略对象管理策略对象通常是无状态的可以被多个上下文共享如果策略需要配置参数可以通过构造函数传入3. 策略模式的应用场景3.1 电商系统中的折扣策略电商平台通常有多种促销方式会员折扣不同等级不同折扣满减优惠限时折扣组合优惠使用策略模式可以灵活组合这些促销策略public interface PromotionStrategy { double applyPromotion(Order order); } public class CompositePromotion implements PromotionStrategy { private ListPromotionStrategy strategies; public double applyPromotion(Order order) { double finalPrice order.getOriginalPrice(); for(PromotionStrategy strategy : strategies) { finalPrice strategy.applyPromotion(order); order.setCurrentPrice(finalPrice); } return finalPrice; } }3.2 支付系统设计支付系统需要支持多种支付方式信用卡支付支付宝微信支付PayPal银行转账策略模式实现public interface PaymentStrategy { boolean pay(double amount); } public class PaymentContext { public boolean executePayment(PaymentStrategy strategy, double amount) { return strategy.pay(amount); } }3.3 游戏开发中的应用游戏中的AI行为、角色技能等都可以使用策略模式public interface AIStrategy { void execute(); } public class AggressiveAI implements AIStrategy { public void execute() { // 攻击性行为逻辑 } } public class DefensiveAI implements AIStrategy { public void execute() { // 防御性行为逻辑 } } public class NPCAI { private AIStrategy strategy; public void setStrategy(AIStrategy strategy) { this.strategy strategy; } public void performAction() { strategy.execute(); } }4. 策略模式的优缺点分析4.1 优势开闭原则无需修改上下文即可引入新策略消除条件语句避免大量的if-else或switch-case语句算法复用相同策略可以被不同上下文使用灵活性运行时可以切换策略单一职责每个策略类只负责一个算法4.2 局限性客户端必须了解策略差异客户端需要知道不同策略的区别以选择合适的策略策略对象增多当策略很多时会产生大量策略类通信开销策略与上下文之间可能需要交换数据增加复杂性对象创建开销频繁创建和销毁策略对象可能影响性能5. 策略模式的最佳实践5.1 与工厂模式结合将策略的创建逻辑封装到工厂中public class StrategyFactory { public static DiscountStrategy getDiscountStrategy(String discountType) { switch(discountType) { case FIXED: return new FixedDiscount(10); case PERCENTAGE: return new PercentageDiscount(5); default: return new NoDiscount(); } } } // 客户端使用 DiscountStrategy strategy StrategyFactory.getDiscountStrategy(FIXED); context.setStrategy(strategy);5.2 使用枚举简化策略管理public enum DiscountType { NONE { public DiscountStrategy getStrategy() { return new NoDiscount(); } }, FIXED { public DiscountStrategy getStrategy() { return new FixedDiscount(10); } }, PERCENTAGE { public DiscountStrategy getStrategy() { return new PercentageDiscount(5); } }; public abstract DiscountStrategy getStrategy(); } // 使用方式 context.setStrategy(DiscountType.FIXED.getStrategy());5.3 策略模式与Lambda表达式在Java 8中可以使用函数式接口和Lambda简化策略模式FunctionalInterface public interface DiscountStrategy { double applyDiscount(double originalPrice); } // 策略定义 DiscountStrategy noDiscount price - price; DiscountStrategy fixedDiscount price - price - 10; DiscountStrategy percentageDiscount price - price * 0.9; // 使用方式 context.setStrategy(fixedDiscount);6. 常见问题与解决方案6.1 如何选择策略常见的策略选择方式客户端显式选择由客户端代码直接指定基于配置的选择从配置文件或数据库读取策略类型自动选择策略根据上下文状态自动选择合适策略// 自动选择策略示例 public DiscountStrategy autoSelectStrategy(Order order) { if(order.getTotalAmount() 1000) { return new PercentageDiscount(10); } else if(order.getCustomer().isVIP()) { return new FixedDiscount(50); } else { return new NoDiscount(); } }6.2 策略之间如何共享数据通过上下文传递将共享数据放在Context中策略链模式一个策略处理完后将结果传递给下一个策略参数对象将多个参数封装成一个参数对象传递6.3 如何处理策略组合使用组合策略模式public class CompositeStrategy implements DiscountStrategy { private ListDiscountStrategy strategies; public double applyDiscount(double originalPrice) { double currentPrice originalPrice; for(DiscountStrategy strategy : strategies) { currentPrice strategy.applyDiscount(currentPrice); } return currentPrice; } }7. 策略模式与其他模式的关系7.1 策略模式 vs 状态模式相似点都有上下文类和多个具体实现类都通过委托来实现行为不同点策略模式客户端主动选择策略状态模式状态转换由内部条件决定7.2 策略模式 vs 命令模式相似点都将行为封装成对象不同点策略模式关注算法选择命令模式关注请求的封装和排队7.3 策略模式 vs 模板方法模式相似点都用于算法变化不同点策略模式通过对象组合实现模板方法通过类继承实现8. 实际项目中的经验分享8.1 性能优化技巧策略对象复用对于无状态策略可以创建单例策略缓存使用缓存避免重复创建策略对象延迟加载策略按需加载减少启动时间public class StrategyCache { private static MapString, DiscountStrategy cache new HashMap(); public static DiscountStrategy getStrategy(String type) { if(!cache.containsKey(type)) { synchronized (cache) { if(!cache.containsKey(type)) { cache.put(type, createStrategy(type)); } } } return cache.get(type); } private static DiscountStrategy createStrategy(String type) { // 创建策略的逻辑 } }8.2 测试策略单元测试每个策略确保每个策略独立正确上下文测试验证上下文是否正确使用策略策略切换测试测试运行时策略切换的正确性Test public void testStrategySwitch() { DiscountContext context new DiscountContext(); context.setStrategy(new FixedDiscount(10)); assertEquals(90, context.executeStrategy(100), 0.001); context.setStrategy(new PercentageDiscount(10)); assertEquals(90, context.executeStrategy(100), 0.001); }8.3 常见陷阱策略膨胀避免创建过多细粒度策略过度设计简单条件判断可能比策略模式更合适上下文臃肿不要把太多逻辑放在Context中策略泄漏避免策略类依赖Context内部状态在实际项目中我经常看到开发者过度使用策略模式。一个经验法则是当你有多个条件分支处理相似但不同的算法并且这些算法可能在将来会变化或扩展时才考虑使用策略模式。对于简单、稳定的条件逻辑简单的if-else可能更合适。
企业数字化 ERP 产品动态
相关推荐
Linux下MySQL客户端开发:头文件与库文件定位及32/64位编译链接避坑指南 简介:面向在 Linux 环境下进行 C/C 开发、需要连接 MySQL 数据库的开发者,这份资源提供编译期所需的头文件与库文件,省去安装 mysql-devel 或部署完整客户端与服务端的麻烦。压缩包共 77 个文件,以 68 个 .h 头文件、8 个 .a 静态… · 2026/11/3 13:54:35
SQL Server餐厅点餐系统课程设计:事务/触发器/存储过程实战 简介:本资源是一份面向高校数据库课程设计实践的SQL Server餐厅点餐系统完整实现,适用于计算机、信息管理等专业本科生开展数据库原理与应用开发综合训练。系统聚焦餐饮场景核心业务,通过菜品管理、消费记录、包厢调度、员工维护等模块&#… · 2026/11/3 6:41:21
CMake 3.25 Windows C++构建指南:生成器、Presets与避坑 简介:这份资源面向在 Windows 平台上从事 C 开发、需要统一构建流程的工程师与学习者,提供 CMake 3.25 的官方 Windows 版本,用于替代手写 Makefile、在 Visual Studio、MinGW、Ninja 等不同编译环境间快速生成工程文件并完成配置与构建。资源… · 2026/11/4 22:09:52
煤矿电工证是什么证 怎么报名才不走弯路 煤矿电工证是什么证 怎么报名才不走弯路 刚毕业找不到工作?煤矿电工证是你打开门的钥匙!你是不是也跟小李一样,拿着工程专业的毕业证,却连面试机会都难争取?别急,煤矿电工证就是你的突破口,但怎么报名才能不走弯路,咱们一起说清楚。… · 2026/11/13 7:38:08
石林电工证报名通过率揭秘:学历不高怕报不上名?看过来 石林电工证报名通过率揭秘:学历不高怕报不上名?看过来 你是不是也这样想:自己学历不高,考个电工证是不是就没戏了?别急,今天咱们就来聊一聊【石林电工证报名】这事,尤其是那些觉得自己学历不够,但又想入行的朋友们。别看学历高不高,关键看你有没有真… · 2026/11/13 7:38:08
电工证和货运资格证怎么考?实操考试心里没底怕挂科?官方报名入口全攻略 电工证和货运资格证怎么考?实操考试心里没底怕挂科?官方报名入口全攻略 实操考试心里没底怕挂科?这是很多漯河公路工程从业者在报考电工证和货运资格证时最真实的感受。尤其是像你这样,已经在一线工作多年,但面对新政策、新要求,总担心自己会跟不上,或… · 2026/11/13 7:38:08
电工证ic卡真假辨别在哪考别再被坑了 电工证ic卡真假辨别在哪考别再被坑了 怕考不过白交培训费?别急,你不是一个人。每年都有不少人因为电工证ic卡真假辨别不清,结果花了钱还拿不到证,甚至被忽悠去“哪里考”都搞不明白。这篇文章就是帮你理清楚电工证ic卡真假辨别的方法,同时告诉你… · 2026/11/13 7:38:08
禅城考电工证哪里进去 良心建议:学历不高也能考 禅城考电工证哪里进去 良心建议:学历不高也能考 你是不是也在琢磨“ 禅城考电工证哪里进去 ”,还担心自己学历不高,怕报不上名?别急,老电工给你说句 良心建议 :只要符合基本条件,学历不是拦路虎,关键是你要知道怎么走流程、怎么准备资料。… · 2026/11/13 7:38:08
特色的特种工考证价格保姆级教程怎么考 特色的特种工考证价格保姆级教程怎么考 怕考不过白交培训费?这期保姆级教程直接给你讲清楚,特色的特种工考证价格到底怎么选,怎么报,怎么考,别再踩坑了。 1. 特色的特种工考证价格是多少?会不会有隐形收费? 在洛阳涧西区,… · 2026/11/13 7:37:08
电工证丢失还能补吗?千万别踩坑,丢了证等于失业 电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。… · 2026/11/12 14:09:01
电力电缆作业证直播报名入口与办理流程良心建议 电力电缆作业证直播报名入口与办理流程良心建议 你是不是也担心学历不高报不了名?别急,今天就给你讲讲 电力电缆作业证直播 的报名流程和那些你必须知道的干货, 良心建议 在这里,别错过。 电力电缆作业证直播报名需要什么条件?… · 2026/11/13 5:40:45
英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 英德电工证报考费多少钱,怕考不过白交培训费?看完这篇别再踩坑 怕考不过白交培训费?英德电工证报考费多少钱,你真的了解吗?现在市面上培训机构五花八门,价格参差不齐,很多人一不小心就花了冤枉钱,结果还考不过。别急,今天就来给你说清楚英德电工证的… · 2026/11/12 23:27:43
维修电公用考电工证吗 在哪考最靠谱 维修电公用考电工证吗 在哪考最靠谱 工地太忙根本没时间复习考试,你是维修电工,天天在项目上跑,连抽个空背个题都难。那问题来了—— 维修电公用考电工证吗 ?答案是: 必须考 。尤其是在当前施工行业,没有电工证,连进场都可能被拦下。而且,… · 2026/11/13 0:00:08
电工证是不是可以登高?含金量和证书范围你必须知道的事 电工证是不是可以登高?含金量和证书范围你必须知道的事 证书过期了不知道怎么复审延期,这事儿很多人遇到过,尤其是像你这样在郑州金水区做劳务班组负责人,手里握着几十个工人的证书,稍微一疏忽,就可能影响工程进度和公司信誉。特别是电工证是不是可以登… · 2026/11/13 0:00:08
鸡西电工证哪家下证快官方报名入口怎么找 鸡西电工证哪家下证快官方报名入口怎么找 你是不是也担心 学历不高怕报不上名 ?别急,今天我就来跟你说说, 鸡西电工证哪家下证快 ,还有 官方报名入口 到底怎么找,别让那些“代办”“代考”耽误了你的机会。… · 2026/11/13 0:00:08
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/13 6:12:21
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/13 6:11:51
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/12 21:15:21