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

面向对象设计模式——策略模式

策略设计模式(Strategy Pattern)是一种行为型设计模式,它允许在运行时选择算法的行为。该模式定义了一系列算法,将每个算法封装到一个独立的类中,使它们可以相互替换。策略模式使算法独立于客户端而变化,客户端可以根据需要选择不同的算法。

主要组成部分:

  1. 策略接口(Strategy Interface):定义了一组算法的通用接口,所有具体策略类都要实现这个接口。

  2. 具体策略类(Concrete Strategies):实现策略接口,提供不同的算法实现。

  3. 上下文(Context):维护一个对策略接口的引用,允许客户端在运行时选择算法。上下文通常会将客户端的请求委派给具体策略对象。

应用场景:

  1. 动态选择算法:策略模式适用于需要在运行时根据不同情况切换算法的情况。例如,排序算法,日志记录级别,数据校验等。

  2. 消除大量的条件语句:当一个类有很多条件语句来选择不同的行为时,策略模式可以减少这些条件语句,使代码更具可读性和可维护性。

  3. 复用性:策略模式可以促进算法的复用,不同的上下文可以共享相同的策略对象,减少重复编码。

  4. 解耦合:策略模式将算法的实现与调用代码解耦,这意味着对算法的更改不会影响调用它的代码。

示例:

考虑一个电商平台的购物车系统。不同用户可能有不同的折扣策略,例如普通用户、VIP用户、员工用户可以享受不同的折扣。使用策略模式可以创建一个折扣策略接口,然后为每个用户类型创建具体的策略类。购物车上下文对象可以接收不同用户类型的策略,并在结算时应用相应的折扣策略。

这里是一个伪代码示例:

// 策略接口
interface DiscountStrategy {double applyDiscount(double totalAmount);
}// 具体策略类
class RegularCustomerDiscount implements DiscountStrategy {public double applyDiscount(double totalAmount) {return totalAmount;}
}class VIPCustomerDiscount implements DiscountStrategy {public double applyDiscount(double totalAmount) {return totalAmount * 0.9; // 10% off}
}class EmployeeDiscount implements DiscountStrategy {public double applyDiscount(double totalAmount) {return totalAmount * 0.8; // 20% off}
}// 上下文
class ShoppingCart {private DiscountStrategy discountStrategy;public ShoppingCart(DiscountStrategy strategy) {this.discountStrategy = strategy;}public double checkout(double totalAmount) {return discountStrategy.applyDiscount(totalAmount);}
}

在这个示例中,不同用户类型对应于不同的具体策略类。购物车上下文可以根据用户类型选择不同的策略,而不需要改变购物车的代码。这使得系统更加灵活,并且可以轻松应对不同的折扣需求。

策略模式是如何消除条件语句的?

策略模式消除条件语句的关键在于将不同的行为封装到各个具体策略类中,而不再需要在上下文类(调用者)中使用大量的条件语句来选择不同的行为。这通过以下方式实现:

  1. 抽象策略接口:首先,策略模式定义了一个抽象策略接口,该接口声明了一组通用的方法,这些方法将被不同的具体策略类实现。这些方法代表不同的行为或算法。

  2. 具体策略类:每个具体策略类都实现了策略接口中的方法,提供了特定的行为或算法实现。每个具体策略类代表了一种行为的变体。

  3. 上下文类:上下文类包含一个策略接口的引用,客户端可以将不同的策略对象传递给上下文类。上下文类使用策略对象执行特定的行为,而不需要了解具体策略的细节。

通过上述步骤,策略模式将条件语句的选择逻辑从客户端移到了上下文类中,客户端只需要选择合适的策略对象传递给上下文,而不再需要编写大量的if-else语句来决定采用哪种行为。

以下是示例代码,演示如何通过策略模式消除条件语句:

// 抽象策略接口
interface PaymentStrategy {void pay(int amount);
}// 具体策略类
class CreditCardPayment implements PaymentStrategy {public void pay(int amount) {// 实现信用卡支付逻辑}
}class PayPalPayment implements PaymentStrategy {public void pay(int amount) {// 实现PayPal支付逻辑}
}// 上下文类
class ShoppingCart {private PaymentStrategy paymentStrategy;public void setPaymentStrategy(PaymentStrategy strategy) {this.paymentStrategy = strategy;}public void checkout(int amount) {paymentStrategy.pay(amount); // 执行支付,不需要条件语句}
}

在上述示例中,ShoppingCart 上下文类可以使用不同的 PaymentStrategy 对象,无需在 checkout 方法中包含条件语句。策略模式将不同的支付逻辑封装在具体策略类中,使代码更加可维护和可读。

为什么说算法可以相互替换?

是的,不同的行为在策略模式中通常对应不同的算法。策略模式的目标之一是将不同的算法封装到各个独立的策略类中,以使它们可以相互替换,这是因为这些算法执行的是相同的任务,但它们可以使用不同的方法来完成。

策略模式的关键在于实现了开闭原则,即对扩展开放,对修改关闭。这意味着可以轻松地添加新的策略(算法),而无需修改已有的代码。这种灵活性使不同的算法可以相互替换,而不会影响上下文类或客户端的代码。

举例来说,考虑一个排序算法的上下文。在这个上下文中,可以有多个策略(算法)来执行不同的排序任务,如冒泡排序、快速排序、归并排序等。每个排序算法都被封装在一个具体的策略类中。如果要更改排序算法,只需创建一个新的策略类并将其传递给上下文类,而不需要修改已有的排序上下文的代码。

策略模式的目的是提供一种简单的方式来交换算法,以满足不同的需求,同时保持代码的可维护性和可扩展性。这种灵活性使算法可以相互替换,而不会对系统的其他部分产生负面影响。

策略模式在应用场景下会和哪些其他设计模式一起使用?

策略模式通常可以与以下设计模式一起使用:

  1. 工厂模式:用于创建具体策略对象的工厂方法,以避免直接实例化具体策略类。

  2. 单例模式:可以用来确保策略对象是唯一的,尤其是在多个地方需要使用相同的策略时。

  3. 装饰器模式:允许你在不修改策略对象的情况下动态地添加额外的行为或功能。

  4. 观察者模式:可以通过观察者模式通知其他对象有关策略的变化,以便它们可以适应新的策略。

策略模式通常用于解耦算法的定义和使用,使系统更具弹性和可维护性。
让我们以一个示例来说明如何将策略模式与其他设计模式一起使用。

场景:假设我们有一个电商平台,我们需要实现一个促销策略,用户可以根据促销策略来获得不同的折扣。这里,我们使用策略模式来处理促销策略的不同算法,而工厂模式用于创建策略对象,单例模式确保策略对象的唯一性,装饰器模式用于动态添加额外的促销信息,观察者模式用于通知用户有关促销策略的变化。

首先,我们定义策略接口:

// 策略接口
interface PromotionStrategy {double applyDiscount(double amount);
}

然后,实现具体的促销策略:

// 具体策略类
class BlackFridayPromotion implements PromotionStrategy {public double applyDiscount(double amount) {// 实现 Black Friday 促销算法}
}class ChristmasPromotion implements PromotionStrategy {public double applyDiscount(double amount) {// 实现圣诞促销算法}
}

接下来,使用工厂模式创建策略对象:

// 策略工厂
class PromotionStrategyFactory {private static PromotionStrategy blackFriday = new BlackFridayPromotion();private static PromotionStrategy christmas = new ChristmasPromotion();public static PromotionStrategy getPromotionStrategy(String promotionType) {if ("BlackFriday".equals(promotionType)) {return blackFriday;} else if ("Christmas".equals(promotionType)) {return christmas;}// 其他策略return null;}
}

使用单例模式来确保策略对象的唯一性:

// 单例模式
class PromotionStrategySingleton {private static PromotionStrategy instance;private PromotionStrategySingleton() {// 私有构造函数}public static PromotionStrategy getInstance() {if (instance == null) {instance = PromotionStrategyFactory.getPromotionStrategy("Default"); // 默认策略}return instance;}
}

使用装饰器模式来添加额外的促销信息:

// 装饰器模式
class PromotionDecorator implements PromotionStrategy {private PromotionStrategy strategy;private String additionalInfo;public PromotionDecorator(PromotionStrategy strategy, String additionalInfo) {this.strategy = strategy;this.additionalInfo = additionalInfo;}public double applyDiscount(double amount) {// 添加额外信息的处理return strategy.applyDiscount(amount);}
}

最后,使用观察者模式通知用户有关促销策略的变化:

// 观察者模式
interface PromotionObserver {void updatePromotion(String promotionInfo);
}class User implements PromotionObserver {private String username;public User(String username) {this.username = username;}public void updatePromotion(String promotionInfo) {System.out.println(username + " received promotion info: " + promotionInfo);}
}class PromotionSubject {private List<PromotionObserver> observers = new ArrayList<>();public void addObserver(PromotionObserver observer) {observers.add(observer);}public void notifyObservers(String promotionInfo) {for (PromotionObserver observer : observers) {observer.updatePromotion(promotionInfo);}}
}

这个示例展示了如何将策略模式与工厂模式、单例模式、装饰器模式和观察者模式一起使用,以处理促销策略的不同算法,确保策略对象的唯一性,动态添加额外信息,并通知用户有关促销策略的变化。

相关文章:

面向对象设计模式——策略模式

策略设计模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许在运行时选择算法的行为。该模式定义了一系列算法&#xff0c;将每个算法封装到一个独立的类中&#xff0c;使它们可以相互替换。策略模式使算法独立于客户端而变化&#xff0c;客…...

Kubernetes - Ingress HTTP 负载搭建部署解决方案(新版本v1.21+)

在看这一篇之前&#xff0c;如果不了解 Ingress 在 K8s 当中的职责&#xff0c;建议看之前的一篇针对旧版本 Ingress 的部署搭建&#xff0c;在开头会提到它的一些简介Kubernetes - Ingress HTTP 负载搭建部署解决方案_放羊的牧码的博客-CSDN博客 开始表演 1、kubeasz 一键安装…...

刚刚:腾讯云3年轻量2核2G4M服务器优惠价格366元三年

腾讯云3年轻量2核2G4M服务器&#xff0c;2023双十一优惠价格366元三年&#xff0c;自带4M公网带宽&#xff0c;下载速度可达512KB/秒&#xff0c;300GB月流量&#xff0c;50GB SSD盘系统盘&#xff0c;腾讯云百科txybk.com分享腾讯云轻量2核2G4M服务器性能、优惠活动、购买条件…...

`include指令【FPGA】

案例&#xff1a; 在Verilog中&#xff0c;include指令可以将一个文件的内容插入到当前文件中。 这个指令通常用于将一些常用的代码片段或者模块定义放在单独的文件中&#xff0c; 然后在需要使用的地方通过include指令将其插入到当前文件中。 这样可以提高代码的复用性和可维…...

iphone备份后怎么转到新手机,iphone备份在哪里查看

iphone备份会备份哪些东西&#xff1f;iphone可根据需要备份设备数据、应用数据、苹果系统等。根据不同的备份数据&#xff0c;可备份的数据类型不同&#xff0c;有些工具可整机备份&#xff0c;有些工具可单项数据备份。本文会详细讲解苹果手机备份可以备份哪些东西。 一、ip…...

JAVA毕业设计106—基于Java+Springboot的外卖系统(源码+数据库)

基于JavaSpringboot的外卖系统(源码数据库)106 一、系统介绍 本系统分为用户端和管理端角色 前台用户功能&#xff1a; 登录、菜品浏览&#xff0c;口味选择&#xff0c;加入购物车&#xff0c;地址管理&#xff0c;提交订单。 管理后台&#xff1a; 登录&#xff0c;员工管…...

SpringCore完整学习教程4,入门级别

本章从第4章开始 4. Logging Spring Boot使用Commons Logging进行所有内部日志记录&#xff0c;但保留底层日志实现开放。为Java Util Logging、Log4J2和Logback提供了默认配置。在每种情况下&#xff0c;记录器都预先配置为使用控制台输出和可选的文件输出。 默认情况下&…...

如何能在项目具体编码实现之前能尽可能早的发现问题并解决问题

在项目的具体编码实现之前尽可能早地发现并解决问题&#xff0c;可以大大节省时间和资源&#xff0c;提高项目的成功率。以下是一些策略和方法&#xff1a; 1. 明确需求和预期&#xff1a; 确保所有的项目需求都是清晰和明确的。需求模糊不清是项目失败的常见原因之一。与利益…...

Windows server服务器允许多用户远程的设置

在Windows Server上允许多用户同时进行远程桌面连接&#xff0c;您需要配置远程桌面服务以支持多用户并确保许可证和授权允许多用户连接。以下是在Windows Server上允许多用户远程桌面连接的步骤&#xff1a; 注意&#xff1a;这些步骤适用于 Windows Server 2012、Windows Ser…...

Vmware下的虚拟机NAT连接后仍然木有网络

问题描述 出现在主机能ping通&#xff0c;互联网ping不通的情况。 废话 假设已经设置了网络配置文件IPADDR。 那么&#xff0c;NAT后可以访问互联网的前提是&#xff1a;这个IPADDR的网段在Vmware软件设置的网段内。 解决 在Vmware虚拟网络设置选项卡中&#xff0c;进NAT配…...

2.Vue — 模板语法、数据绑定、el与data的写法、数据代理

文章目录 一、模板语法1.1 插值语法1.2指令语法 二、数据绑定语法2.1 单向数据绑定2.2 双向数据绑定 三、el与data的两种写法3.1 el3.2 data 四、数据代理4.1 Object.defineProperty4.2 Vue数据代理4.2.1 展示数据代理4.2.2 Vue数据代理 一、模板语法 root容器里面的代码被称为…...

管理类联考——数学——汇总篇——知识点突破——数据分析——记忆

文章目录 考点记忆/考点汇总——按大纲 整体目录大纲法记忆宫殿法绘图记忆法 局部数字编码法对号不对号 归类记忆法重点记忆法歌决记忆法口诀&#xff1a;加法分类&#xff0c;类类相加&#xff1b;乘法分步&#xff0c;步步相乘。 谐音记忆法涂色 理解记忆法比较记忆法转图像记…...

springboot+mybatis-plus实现读写分离

shigen坚持日更的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。坚持记录和分享从业两年以来的技术积累和思考&#xff0c;不断沉淀和成长。 最近shigen加班也比较严重&#xff0c;很多天文章没有更新了&#xff0c;各位读者和伙伴见…...

java将list转为逗号隔开字符串,将逗号连接的字符串转成字符数组,​将逗号分隔的字符串转换为List​(Java逗号分隔-字符串与数组相互转换)

一、通过testList.stream().collect(Collectors.joining(",")) &#xff0c;通过流转换&#xff0c;将list转为逗号隔开字符串 List<String> testList new ArrayList<>(); testList.add("test1"); testList.add("test2"); testList…...

2023高频前端面试题-CSS

1. CSS 选择器的优先级是怎么样的&#xff1f; CSS 选择器的优先级顺序&#xff1a; 内联样式 > ID选择器 > 类选择器 > 标签选择器 优先级的计算&#xff1a; 优先级是由 A、B、C、D 四个值来决定的&#xff0c;具体计算规则如下 A{如果存在内联样式则为 1&…...

我会在以下情况用到GPT

ChatGPT可以在各种情况下派上用场&#xff0c;包括但不限于以下情况&#xff1a; 获取信息&#xff1a;你可以使用ChatGPT来获取关于各种主题的信息&#xff0c;例如历史事件、科学知识、文化背景等。ChatGPT可以用作一个知识库&#xff0c;回答你的问题。 学习新知识&#xf…...

33:深入浅出x86中断机制

背景 我们知道使用0x10号中断&#xff0c;可以在屏幕上打印一个字符。 问题 系统中的 中断 究竟是什么&#xff1f; 生活中的例子 来看一个生活中例子&#xff1a; 小狄的工作方式 在处理紧急事务的时候&#xff0c;不回应同事的技术求助。老板的召唤必须回应&#xff0c;…...

docker docker-compose安装(centos7)

docker安装 1.卸载旧版 卸载旧版 yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine2.安装一个yum工具 yum install -y yum-utils3.配置docker的yum源 yum-config-manager -…...

Dockerfile文件详细教程

写在前面 Dockerfile是用来构建镜像的&#xff0c;他实际上就是把在linux下的命令操作写到了Dockerfile中&#xff0c;通过Dockerfile去执行设置好的操作命令&#xff0c;保证通过Dockerfile的构建镜像是一致的。 实战分析 该例子来自于 chromium 项目 主要干的事情&#xf…...

机器学习-模型评估与选择

文章目录 评估方法留出法交叉验证自助法 性能的衡量回归问题分类问题查准率、查全率与F1ROC与AUC 在机器学习中&#xff0c;我们通常面临两个主要问题&#xff1a;欠拟合和过拟合。欠拟合指模型无法在训练数据上获得足够低的误差&#xff0c;通常是因为模型太简单&#xff0c;无…...

分享一下办公自动化常用的思想

目录 网页获取数据需求①大体思路&#xff1a;PythonseleniumXpath 网页获取数据需求②大体思路&#xff1a;requests爬虫 批量生成需求①文件的移动、重命名②word、Excel批量生成 匹配需求 网页获取数据需求① 大体思路&#xff1a;PythonseleniumXpath 我们在利用Python做…...

mac vscode 使用 clangd

C 的智能提示 IntelliSense 非常不准&#xff0c;我们可以使用 clangd clangd 缺点就是配置繁琐&#xff0c;优点就是跳转和提示代码精准 开启 clangd 之后会提示你关闭 IntelliSense 1、安装插件 clangd 搜索第一个下载多的就是 2、配置 clangd 可执行程序路径 clangd 插…...

DSI及DPHY的学习

DSI的物理层PHY只能是DPHY 本节讲述的DSI是V1.02.00---2010.6.28 从DSI V1.02开始DSI支持图像数据包RGB和YCbCr的传输&#xff0c;在此版本之前只支持RGB传输。 本节内容与CSICDPHY相同时 请参考&#xff1a; CSI2与CDPHY学习-CSDN博客 同时本节会做一些与CSICDPHY的比较 …...

环形链表(C++解法)

题目 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#…...

星闪技术 NearLink 一种专门用于短距离数据传输的新型无线通信技术

本心、输入输出、结果 文章目录 星闪技术 NearLink 一种专门用于短距离数据传输的新型无线通信技术前言星闪技术 NearLink 的诞生背景星闪技术 NearLink 简介星闪技术 NearLink 技术是一种蓝牙技术吗星闪技术 NearLink 优势星闪技术 NearLink 应用前景弘扬爱国精神星闪技术 Nea…...

【Python机器学习】零基础掌握RandomForestRegressor集成学习

如何预测房价是不是一直困扰着大家?特别是在房地产市场波动不定的情况下,这样的预测可以说是切实需要。 要解决这个问题,一个可行的方法是利用历史房价数据和房屋的各种属性(如面积、楼层、地理位置等)进行分析。通过这些数据,可以用一个模型来预测未来房价。 假设有以…...

FreeRTOS深入教程(任务创建的深入和任务调度机制分析)

文章目录 前言一、深入理解任务的创建二、任务的调度机制1.FreeRTOS中任务调度的策略2.FreeRTOS任务调度策略实现的核心3.FreeRTOS内部链表源码解析4.如何通过就绪链表管理任务的执行顺序 三、一个任务能够运行多久1.高优先级任务可抢占低优先级任务一直运行2.相同优先级的任务…...

Megatron-LM GPT 源码分析(一) Tensor Parallel分析

引言 本文基于开源代码 GitHub - NVIDIA/Megatron-LM: Ongoing research training transformer models at scale &#xff0c;通过GPT的模型运行示例&#xff0c;从三个维度 - 模型结构、代码运行、代码逻辑说明 对其源码做深入的分析。 Tensor Parallel源码分析...

分类预测 | MATLAB实现SSA-CNN-GRU麻雀算法优化卷积门控循环单元数据分类预测

分类预测 | MATLAB实现SSA-CNN-GRU麻雀算法优化卷积门控循环单元数据分类预测 目录 分类预测 | MATLAB实现SSA-CNN-GRU麻雀算法优化卷积门控循环单元数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现SSA-CNN-GRU麻雀算法优化卷积门控循环单元数据…...

婚礼的魅力

昨日有幸被邀请去当伴郎&#xff0c;虽然是替补&#xff0c;即别人鸽了&#xff0c;过去救急&#xff0c;但总归是去起作用。 婚礼的魅力&#xff0c;感受到了&#xff0c;满满的仪式感&#xff0c;紧凑的流程&#xff0c;还有不断的拍照&#xff0c;做视频&#xff0c;留下美好…...