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

设计模式-策略模式:从鞋厂促销活动看算法的灵活切换

在商业竞争中,灵活的营销策略是企业抢占市场的关键。比如一家鞋厂,在不同场景下会采用不同的促销方式:日常满减、节假日打折、会员双倍积分……如果每次换促销活动都要大改系统,不仅效率低下,还容易出错。

软件开发中也存在类似需求:同一业务目标(如计算价格、排序数据)有多种实现算法,且需要根据场景动态切换。策略模式(Strategy Pattern)正是为这种“算法族动态切换”设计的模式,它将不同算法封装成独立策略,让算法的选择与使用彻底解耦。

本文将以鞋厂的促销活动为实例,详解策略模式的原理、实现及实战价值。

一、为什么需要策略模式?——从混乱的促销代码说起

假设鞋厂最初的促销系统是这样实现的:根据促销类型用if-else判断逻辑,计算最终价格:

// 订单类(包含混乱的促销逻辑)
public class Order {private double price; // 原价private String promotionType; // 促销类型:"fullReduce"(满减)、"discount"(打折)、"points"(积分)public Order(double price, String promotionType) {this.price = price;this.promotionType = promotionType;}// 计算最终价格(包含所有促销逻辑,混乱不堪)public double calculateFinalPrice() {if ("fullReduce".equals(promotionType)) {// 满减规则:满300减50,满500减100if (price >= 500) {return price - 100;} else if (price >= 300) {return price - 50;} else {return price;}} else if ("discount".equals(promotionType)) {// 打折规则:全场8折return price * 0.8;} else if ("points".equals(promotionType)) {// 积分规则:不降价,但赠送双倍积分System.out.println("赠送" + (int)(price * 2) + "积分");return price;} else {// 默认无促销return price;}}
}// 客户端调用
public class Client {public static void main(String[] args) {Order order1 = new Order(600, "fullReduce");System.out.println("满减后价格:" + order1.calculateFinalPrice());Order order2 = new Order(600, "discount");System.out.println("打折后价格:" + order2.calculateFinalPrice());}
}

这种实现方式存在三个严重问题:

  1. 耦合度高:促销算法与订单类深度绑定,新增或修改促销方式必须修改Order类,违反“开闭原则”。
  2. 可读性差:所有算法逻辑堆砌在calculateFinalPrice方法中,随着促销方式增多,代码会变得臃肿不堪。
  3. 扩展性差:如果需要临时新增“限时秒杀”活动,必须侵入原有代码,容易引发其他促销逻辑的bug。

策略模式的解决方案是:将每种促销算法封装成独立“策略”类,订单类只需根据场景选择对应的策略,无需关心算法细节。就像鞋厂的促销活动,每种活动有独立的规则文档,店员只需按规则执行即可。

二、策略模式的核心结构

策略模式通过四个核心角色实现“算法的封装与切换”:

  1. 抽象策略(Strategy):定义所有具体策略的公共接口(如“计算促销后价格”的方法)。
  2. 具体策略(Concrete Strategy):实现抽象策略接口,封装具体的算法(如满减、打折、积分等促销规则)。
  3. 环境类(Context):持有一个策略对象的引用,负责策略的选择与使用(如订单类根据促销类型选择对应的策略)。
  4. 客户端(Client):创建具体策略对象,并设置到环境类中(如根据用户选择的促销活动,为订单指定策略)。

用一句话概括:环境类通过调用抽象策略接口使用算法,具体使用哪种算法由客户端决定,且可以动态切换

三、策略模式实战:鞋厂的灵活促销系统

场景模拟

鞋厂需要支持多种促销活动,且能随时新增或停用活动:

  • 满减策略:满300减50,满500减100,满1000减300。
  • 打折策略:平日9折,节假日8折(可动态调整折扣率)。
  • 积分策略:不降价,但消费1元赠送2积分(积分可兑换商品)。
  • 组合策略:未来可能新增“满减+积分”的组合活动。

要求系统能根据不同时间、不同用户群体自动切换策略,且新增策略时无需修改原有代码。

代码实现

// 1. 抽象策略:促销策略接口
public interface PromotionStrategy {// 计算促销后的价格double calculate(double originalPrice);// 获取策略描述String getDescription();
}// 2. 具体策略1:满减策略
public class FullReduceStrategy implements PromotionStrategy {@Overridepublic double calculate(double originalPrice) {if (originalPrice >= 1000) {return originalPrice - 300;} else if (originalPrice >= 500) {return originalPrice - 100;} else if (originalPrice >= 300) {return originalPrice - 50;} else {return originalPrice;}}@Overridepublic String getDescription() {return "满减促销:满300减50,满500减100,满1000减300";}
}// 2. 具体策略2:打折策略(支持动态调整折扣率)
public class DiscountStrategy implements PromotionStrategy {private double discountRate; // 折扣率(如0.8表示8折)public DiscountStrategy(double discountRate) {this.discountRate = discountRate;}@Overridepublic double calculate(double originalPrice) {return originalPrice * discountRate;}@Overridepublic String getDescription() {return String.format("打折促销:%.1f折", discountRate * 10);}
}// 2. 具体策略3:积分策略
public class PointsStrategy implements PromotionStrategy {@Overridepublic double calculate(double originalPrice) {// 不改变价格,但赠送积分int points = (int) (originalPrice * 2);System.out.println("赠送" + points + "积分(1积分=0.01元,可兑换商品)");return originalPrice;}@Overridepublic String getDescription() {return "积分促销:消费1元赠送2积分";}
}// 3. 环境类:订单(使用策略计算价格)
public class Order {private double originalPrice; // 原价private PromotionStrategy strategy; // 促销策略// 构造器:传入原价和策略public Order(double originalPrice, PromotionStrategy strategy) {this.originalPrice = originalPrice;this.strategy = strategy;}// 动态切换策略(支持订单创建后更换促销方式)public void setStrategy(PromotionStrategy strategy) {this.strategy = strategy;}// 计算最终价格(委托给策略处理)public double getFinalPrice() {System.out.println("促销方式:" + strategy.getDescription());return strategy.calculate(originalPrice);}
}// 4. 客户端:根据场景选择策略
public class ShoeStore {public static void main(String[] args) {// 场景1:日常满减活动PromotionStrategy fullReduce = new FullReduceStrategy();Order order1 = new Order(600, fullReduce);System.out.println("订单1最终价格:" + order1.getFinalPrice() + "\n");// 场景2:节假日8折活动PromotionStrategy holidayDiscount = new DiscountStrategy(0.8);Order order2 = new Order(600, holidayDiscount);System.out.println("订单2最终价格:" + order2.getFinalPrice() + "\n");// 场景3:会员日积分活动PromotionStrategy points = new PointsStrategy();Order order3 = new Order(600, points);System.out.println("订单3最终价格:" + order3.getFinalPrice() + "\n");// 场景4:动态切换策略(订单创建后改参与打折)order1.setStrategy(new DiscountStrategy(0.9));System.out.println("订单1更换策略后价格:" + order1.getFinalPrice());}
}

运行结果

促销方式:满减促销:满300减50,满500减100,满1000减300
订单1最终价格:500.0促销方式:打折促销:8.0折
订单2最终价格:480.0促销方式:积分促销:消费1元赠送2积分
赠送1200积分(1积分=0.01元,可兑换商品)
订单3最终价格:600.0促销方式:打折促销:9.0折
订单1更换策略后价格:540.0

四、策略模式的灵活性:动态扩展与组合

策略模式的最大优势是支持算法的动态扩展和灵活组合,无需修改现有代码。

场景扩展1:新增组合策略

如果鞋厂推出“满减+积分”的组合促销(满减后再送积分),只需新增一个策略类:

// 新增具体策略:满减+积分组合策略
public class FullReducePlusPointsStrategy implements PromotionStrategy {// 组合两个基础策略private PromotionStrategy fullReduce = new FullReduceStrategy();private PromotionStrategy points = new PointsStrategy();@Overridepublic double calculate(double originalPrice) {// 先计算满减后的价格double priceAfterReduce = fullReduce.calculate(originalPrice);// 再对满减后的价格计算积分(积分策略会打印赠送信息)points.calculate(priceAfterReduce);return priceAfterReduce;}@Overridepublic String getDescription() {return "满减+积分组合促销:满减后再送积分";}
}// 客户端直接使用新策略
Order order4 = new Order(600, new FullReducePlusPointsStrategy());
System.out.println("订单4最终价格:" + order4.getFinalPrice());
// 输出:
// 促销方式:满减+积分组合促销:满减后再送积分
// 赠送1000积分(1积分=0.01元,可兑换商品)
// 订单4最终价格:500.0

场景扩展2:策略工厂管理策略

当策略较多时,可通过“策略工厂”统一管理,避免客户端直接依赖具体策略:

// 策略工厂:根据类型创建策略
public class PromotionStrategyFactory {// 缓存策略实例(避免重复创建)private static Map<String, PromotionStrategy> strategies = new HashMap<>();static {// 初始化策略strategies.put("fullReduce", new FullReduceStrategy());strategies.put("discount8", new DiscountStrategy(0.8));strategies.put("points", new PointsStrategy());}// 根据类型获取策略public static PromotionStrategy getStrategy(String type) {return strategies.getOrDefault(type, new FullReduceStrategy()); // 默认满减}
}// 客户端通过工厂获取策略,无需知道具体实现类
Order order5 = new Order(600, PromotionStrategyFactory.getStrategy("discount8"));

五、策略模式的常见应用场景

从鞋厂促销系统出发,我们可以延伸出策略模式在软件开发中的典型应用:

1. 支付方式选择

电商平台的支付系统支持多种支付方式(支付宝、微信、银联),每种支付方式的接口调用和加密逻辑不同,可用策略模式封装:

  • 抽象策略:PaymentStrategy(定义pay方法)。
  • 具体策略:AlipayStrategyWechatPayStrategy
  • 环境类:OrderPayment(根据用户选择的支付方式调用对应策略)。

2. 排序算法切换

集合排序可根据数据规模选择不同算法(冒泡排序、快速排序、归并排序):

  • 抽象策略:SortStrategy(定义sort方法)。
  • 具体策略:BubbleSortQuickSort
  • 环境类:DataProcessor(根据数据量自动选择策略)。

3. 日志输出方式

日志系统可选择不同输出目标(控制台、文件、数据库):

  • 抽象策略:LogStrategy(定义log方法)。
  • 具体策略:ConsoleLogFileLog
  • 环境类:Logger(根据配置切换输出策略)。

4. 游戏角色技能系统

游戏中角色的技能有不同释放逻辑(物理攻击、魔法攻击、治疗):

  • 抽象策略:SkillStrategy(定义cast方法)。
  • 具体策略:PhysicalAttackMagicAttack
  • 环境类:Role(根据玩家操作切换技能策略)。

六、策略模式的优缺点

优点

  1. 解耦算法与使用:算法的实现与使用分离,环境类无需知道算法细节(如订单类不用关心满减规则)。
  2. 灵活扩展:新增算法只需添加新策略类,无需修改现有代码(符合“开闭原则”)。
  3. 动态切换:支持运行时动态更换算法(如订单创建后切换促销方式)。
  4. 避免多重条件判断:用策略选择替代if-elseswitch,代码更清晰。

缺点

  1. 策略类增多:每种算法对应一个策略类,可能导致类数量增加(可通过策略工厂管理)。
  2. 客户端需了解策略:客户端必须知道所有策略的存在才能选择合适的策略(可通过工厂模式封装选择逻辑)。
  3. 策略间无法共享状态:如果多个策略需要共享数据(如促销活动的起止时间),需额外处理(如将共享数据放入环境类)。

七、策略模式与工厂模式的结合

策略模式解决“算法封装与切换”,工厂模式解决“对象创建”,两者结合可进一步降低客户端复杂度:

  • 工厂模式负责创建策略对象(隐藏策略的实例化细节)。
  • 策略模式负责算法的执行与切换。

就像鞋厂的“促销活动管理系统”:

  • 工厂(PromotionStrategyFactory)负责根据活动类型创建对应的策略对象。
  • 策略(FullReduceStrategy等)负责执行具体的促销计算。
  • 客户端只需告诉工厂“要哪种活动”,无需直接创建策略。

总结:从促销活动到代码设计的启示

策略模式就像鞋厂的促销活动管理:

  • 每种促销方式(具体策略)是独立的规则,可单独设计、修改、停用。
  • 订单系统(环境类)只需按规则计算价格,不关心规则细节。
  • 客户(客户端)可以自由选择活动,系统能动态响应选择。

在代码中,当你遇到“多种算法实现同一目标,且需要动态切换”的场景(如支付方式、排序算法、日志输出),策略模式能让你的代码更清晰、更灵活、更易扩展。


Studying will never be ending.

▲如有纰漏,烦请指正~~

http://www.dtcms.com/a/515696.html

相关文章:

  • Java实现Excel转PDF
  • Fenwick 树进行快速统计
  • Cocos creator2.4.4 处理 16KB 问题
  • 旅游网站的设计的前提成都那家网站做的好
  • undefined reference to `cv::String::dea llocate()‘
  • 计划任务原理及实战
  • 做网站设计最好的公司做旅游网站的论文
  • 【Android】Handler/Looper机制相关的类图和流程图
  • ARM《1》_回顾gcc、动态编译和静态编译、MakeFile的使用
  • 网络环路:隐形威胁的破解之道
  • stm32 can错误中断不处理
  • 我们平常说的连网是指什么?
  • 网站优化人员新乡市延津县建设局网站
  • 网站建设分析从哪几个方面东莞市招聘网
  • 设计模式-责任链模式:从鞋厂审批流程看请求处理的艺术
  • 21_AI智能体开发架构搭建之基于Flask蓝图模块化构建可扩展的知识库服务实践
  • 【手机篇】AI深度学习在手机摄像头模组支架外观检测应用方案
  • 手机版矩阵系统源码搭建与定制开发:深度技术解析与落地实践
  • 做网站首页可以用传媒公司吗软件 项目管理系统
  • 舟山建设工程信息网站北京设计公司招聘
  • Elasticsearch还有哪些常用的分词器?
  • 使用CNN构建VAE
  • TESOLLO:使用MANUS Franka机械臂提高机器人灵活性
  • 西宁建设网站软件陕西交通建设有限公司网站
  • COMAU柯马焊接机器人气保焊省气
  • 西门子 1500 PLC 依托 Ethernet/ip 转 Modbus RTU联合发那科机器人优化生产流程
  • 全球首个超声多模态大模型!百度百舸支撑海豚智能实现高效训练与稳定服务
  • 统一机器人描述格式---URDF
  • SCARA 机器人点到点(PTP)轨迹规划方法
  • 岳阳市网站建设推广搜索引擎优化是什么?