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

行为模式-策略模式

定义:

        Define a family of algorithms,encapsulate each one,and make them interchangeable.(定义一组 算法,将每个算法都封装起来,并且使它们之间可以互换。)

策略模式通用类图

        策略设计模式的核心是封装变化。它把不同的算法或行为封装成独立的策略类,这些策略类实现相同的策略接口。客户端持有策略接口的引用,通过切换具体的策略对象,就能改变自身的行为。这种设计方式将算法的实现细节与客户端分离,使得客户端代码更加简洁,同时方便新增或修改算法策略,符合开闭原则,提高了系统的可维护性和可扩展性。

角色:

策略模式包含以下几个核心角色:

1、抽象策略(Strategy)

        抽象策略是一个接口或抽象类,它定义了所有具体策略类都必须实现的方法。这些方法代表了具体策略的行为,为具体策略类提供统一的抽象接口,使得客户端可以以一致的方式使用不同的策略。

2、具体策略(Concrete Strategy)

        具体策略是抽象策略的实现类,每个具体策略类对应一种具体的算法或行为方式。在具体策略类中,实现抽象策略定义的方法,完成具体的业务逻辑。不同的具体策略类可以有不同的实现方式,相互之间可以自由替换。

3、上下文(Context)

        上下文是使用策略的类,它持有一个抽象策略对象的引用,并提供方法让客户端设置具体的策略对象。上下文在执行相关操作时,会调用策略对象的方法,将具体的行为委托给策略对象来完成,而不关心具体策略的实现细节。

代码示例:

        在电商系统中,不同的促销活动有不同的折扣计算方式,如打折、满减、赠品等,使用策略设计模式实现促销策略的灵活切换。

// 抽象策略:促销策略接口

public interface PromotionStrategy {double calculateDiscount(double originalPrice);}

// 具体策略:打折策略

public class DiscountStrategy implements PromotionStrategy {private double discountRate;public DiscountStrategy(double discountRate) {this.discountRate = discountRate;}@Overridepublic double calculateDiscount(double originalPrice) {return originalPrice * discountRate;}}

// 具体策略:满减策略

public class FullReductionStrategy implements PromotionStrategy {private double fullAmount;private double reductionAmount;public FullReductionStrategy(double fullAmount, double reductionAmount) {this.fullAmount = fullAmount;this.reductionAmount = reductionAmount;}@Overridepublic double calculateDiscount(double originalPrice) {if (originalPrice >= fullAmount) {return originalPrice - reductionAmount;}return originalPrice;}}

// 上下文:购物车类

public class ShoppingCart {private PromotionStrategy promotionStrategy;public void setPromotionStrategy(PromotionStrategy promotionStrategy) {this.promotionStrategy = promotionStrategy;}public double calculateFinalPrice(double originalPrice) {return promotionStrategy.calculateDiscount(originalPrice);}}

// 客户端代码

public class StrategyPatternClient {public static void main(String[] args) {ShoppingCart shoppingCart = new ShoppingCart();// 使用打折策略,打8折PromotionStrategy discountStrategy = new DiscountStrategy(0.8);shoppingCart.setPromotionStrategy(discountStrategy);double originalPrice1 = 200;double finalPrice1 = shoppingCart.calculateFinalPrice(originalPrice1);System.out.println("原价:" + originalPrice1 + "元,使用打折策略后的价格:" + finalPrice1 + "元");// 使用满减策略,满150减30PromotionStrategy fullReductionStrategy = new FullReductionStrategy(150, 30);shoppingCart.setPromotionStrategy(fullReductionStrategy);double originalPrice2 = 200;double finalPrice2 = shoppingCart.calculateFinalPrice(originalPrice2);System.out.println("原价:" + originalPrice2 + "元,使用满减策略后的价格:" + finalPrice2 + "元");}}

优点 :

1、提高代码的灵活性和可扩展性:策略设计模式将算法和行为封装成独立的策略类,客户端可以在运行时自由切换策略,无需修改上下文代码。新增策略时,只需创建新的具体策略类实现抽象策略接口,符合开闭原则,方便系统功能的扩展。

2、增强代码的可读性和可维护性:避免了大量条件语句的使用,将不同的算法或行为逻辑分散到具体的策略类中,使代码结构更加清晰,每个策略类的职责单一,便于理解和维护。

3、实现代码复用:具体策略类可以被多个上下文对象复用,减少了代码的重复开发,提高了代码的复用性。例如,在多个电商系统模块中都可以复用相同的促销策略类。


缺点:

1、增加类的数量:每个具体策略都需要一个独立的类来实现,当策略数量较多时,会导致系统中类的数量大幅增加,增加了代码的复杂性和管理难度。

2、客户端需要了解策略细节:客户端在使用策略设计模式时,需要了解不同策略的功能和特点,以便选择合适的策略。这在一定程度上增加了客户端的使用难度,尤其是当策略种类繁多时。

3、策略间的依赖管理:在某些情况下,不同策略之间可能存在依赖关系或数据共享,需要额外处理这些关系,增加了代码的维护成本。例如,某些促销策略可能依赖于商品的库存信息。


使用场景: 

(一)存在多种可互换的算法或行为

        当系统中存在多种不同的算法或行为方式,且这些算法或行为在逻辑上是等价的,可以相互替换时,适合使用策略设计模式。例如,排序算法(冒泡排序、快速排序、归并排序)、加密算法(MD5、SHA - 256)等场景。

(二)需要在运行时动态切换算法或行为

        如果客户端需要在运行时根据不同的条件或用户需求动态地选择不同的算法或行为,策略设计模式可以轻松实现这一需求。比如,在导航软件中,用户可以选择不同的路线规划策略(最短路径、最快路径、躲避拥堵)。

(三)避免使用大量条件语句

        当使用条件语句(如if - else、switch - case)来判断不同算法或行为会导致代码冗长、难以维护时,策略设计模式可以将每个算法或行为封装成独立的策略类,使代码结构更加清晰,易于维护和扩展。

(四)实现代码的复用和扩展

        策略设计模式将算法或行为封装在具体策略类中,这些策略类可以被多个上下文对象复用。同时,新增策略类也非常方便,只需要实现抽象策略接口,符合开闭原则,有利于系统的功能扩展。

        策略设计模式通过将算法和行为封装成独立的策略类,为软件开发提供了一种灵活、高效的解决方案。它在电商促销、游戏开发、算法选择等众多领域有着广泛的应用,能够有效提高代码的灵活性、可扩展性和可维护性。然而,在使用策略设计模式时,也需要注意其带来的类数量增加、客户端使用难度提高等问题。合理运用策略设计模式,能够让我们在面对多种算法或行为切换需求时,编写出更加简洁、优雅且易于维护的代码,使系统在不同策略的切换中保持高效运行。

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

相关文章:

  • 华大北斗TAU1201-1216A00高精度双频GNSS定位模块 自动驾驶专用
  • AWS IAM 最佳安全实践通用指南
  • 从 “洗澡难” 到 “洗得爽”:便携智能洗浴机如何重塑生活?
  • 微服务架构升级:从Dubbo到SpringCloud的技术演进
  • 浏览器自动化方案
  • 创客匠人解析:系统化工具如何重构知识变现效率
  • 在 kubernetes 上安装 jenkins
  • 闲庭信步使用图像验证平台加速FPGA的开发:第十九课——图像拉普拉斯金字塔的FPGA实现
  • Image 和 IMU 时间戳同步
  • 事务~~~
  • JavaScript进阶篇——第五章 对象成员管理与数组遍历优化
  • 密码喷洒复现
  • Thymeleaf 基础语法与标准表达式详解
  • 如何区分Bug是前端问题还是后端问题?
  • LeetCode经典题解:141、判断链表是否有环
  • 【LeetCode】链表相关算法题
  • Node.js Process Events 深入全面讲解
  • 1.3 vue响应式对象
  • FATFS文件系统原理及其移植详解
  • PyTorch 损失函数详解:从理论到实践
  • 嵌入式学习-PyTorch(5)-day22
  • 【深度学习基础】PyTorch中model.eval()与with torch.no_grad()以及detach的区别与联系?
  • Vue 结合 Zabbix API 获取服务器 CPU、内存、GPU 等数据
  • 数据结构自学Day8: 堆的排序以及TopK问题
  • 前端Vue中,如何实现父组件打开子组件窗口等待子组件窗口关闭后继续执行父组件逻辑
  • DeepSeek(18):SpringAI+DeepSeek大模型应用开发之会话日志
  • 单片机(STM32-中断)
  • JS逆向 - YandexSmartCaptcha (worker线程)
  • 基于WebRTC构建应用的可复用模块
  • 下载webrtc M114版本源码只能使用外网googlesource源-命令版