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

重温设计模式--13、策略模式

策略模式介绍

文章目录

      • 策略模式介绍
      • C++ 代码示例

策略模式是一种行为设计模式,它允许在运行时选择算法的行为。该模式将算法的定义和使用分离开来,使得算法可以独立于使用它的客户端而变化,提高了代码的灵活性和可维护性。
在这里插入图片描述

其主要包含以下几个角色:

  1. 抽象策略(Strategy):定义了一个公共接口,用于所有具体策略类实现,这个接口声明了算法的方法签名,客户端通过这个接口来调用具体的算法。
  2. 具体策略(Concrete Strategy):实现了抽象策略接口,提供具体的算法实现逻辑。不同的具体策略类实现了不同的算法,可以根据具体需求进行替换。
  3. 上下文(Context):持有一个对抽象策略的引用,通过这个引用调用具体策略的算法方法。上下文类负责与客户端交互,并根据情况决定使用哪个具体策略。

使用策略模式的好处在于:

  • 可扩展性强:当需要添加新的算法时,只需创建新的具体策略类实现抽象策略接口即可,不需要修改现有代码的核心逻辑,符合开闭原则(对扩展开放,对修改关闭)。
  • 代码复用性高:具体策略类可以在不同的上下文中被复用,只要符合抽象策略定义的接口规范就行。
  • 便于维护和测试:由于每个算法都独立在具体策略类中实现,代码结构清晰,便于单独对各个算法进行维护和测试。

C++ 代码示例

以下是一个简单的用 C++ 实现的策略模式示例,模拟一个电商系统中不同的折扣策略计算商品最终价格的场景。

#include <iostream>
#include <string>// 抽象策略类,定义折扣计算的接口
class DiscountStrategy {
public:virtual double calculateDiscount(double price) = 0;virtual ~DiscountStrategy() {}
};// 具体策略类1:满减折扣策略
class FullReductionStrategy : public DiscountStrategy {
public:double calculateDiscount(double price) override {if (price >= 200) {return price * 0.2;  // 满200减20%}return 0;}
};// 具体策略类2:固定折扣策略
class FixedDiscountStrategy : public DiscountStrategy {
public:double calculateDiscount(double price) override {return price * 0.1;  // 固定打9折}
};// 上下文类,持有折扣策略引用并执行折扣计算
class ShoppingCart {
public:ShoppingCart(DiscountStrategy* strategy) : m_strategy(strategy) {}void setDiscountStrategy(DiscountStrategy* strategy) {m_strategy = strategy;}double calculateFinalPrice(double price) {double discount = m_strategy->calculateDiscount(price);return price - discount;}private:DiscountStrategy* m_strategy;
};int main() {// 创建具体策略对象FullReductionStrategy fullReduction;FixedDiscountStrategy fixedDiscount;// 创建上下文对象,并传入具体策略对象ShoppingCart cart1(&fullReduction);ShoppingCart cart2(&fixedDiscount);double price = 300;std::cout << "使用满减策略,商品价格为 " << price << " 时,最终价格: " << cart1.calculateFinalPrice(price) << std::endl;std::cout << "使用固定折扣策略,商品价格为 " << price << " 时,最终价格: " << cart2.calculateFinalPrice(price) << std::endl;// 更换策略并重新计算价格cart1.setDiscountStrategy(&fixedDiscount);std::cout << "更换为固定折扣策略后,商品价格为 " << price << " 时,最终价格: " << cart1.calculateFinalPrice(price) << std::endl;return 0;
}

下面对上述代码进行详细解释:

  1. 抽象策略类 DiscountStrategy

    • 它定义了一个纯虚函数 calculateDiscount,这个函数接收商品价格作为参数,用于计算折扣金额,返回值是折扣的具体数值(以价格的比例形式体现)。纯虚函数的存在使得这个类成为抽象类,不能直接实例化,必须由具体的子类来实现其 calculateDiscount 方法。
    • 虚析构函数 ~DiscountStrategy() 的定义是为了保证在通过基类指针删除派生类对象时能够正确调用派生类的析构函数,避免内存泄漏等问题,遵循了多态情况下正确析构的原则。
  2. 具体策略类

    • FullReductionStrategy:实现了 DiscountStrategy 抽象策略接口,在 calculateDiscount 方法中定义了满减的折扣逻辑,即当商品价格大于等于200时,给予20%的折扣,否则没有折扣(返回0)。
    • FixedDiscountStrategy:同样实现了抽象接口,其折扣逻辑是固定给予商品价格10%的折扣,无论商品价格具体是多少。
  3. 上下文类 ShoppingCart

    • 它有一个私有成员变量 m_strategy,类型是指向 DiscountStrategy 抽象策略类的指针,通过构造函数或者 setDiscountStrategy 方法来初始化或更换这个指针所指向的具体策略对象。
    • calculateFinalPrice 方法用于根据当前持有的具体策略计算商品的最终价格,它先调用 m_strategy 指向的具体策略对象的 calculateDiscount 方法获取折扣金额,然后用商品原价减去折扣金额得到最终价格。
  4. main 函数部分

    • 首先创建了两个具体策略类的对象 fullReduction(满减策略)和 fixedDiscount(固定折扣策略)。
    • 接着创建了两个 ShoppingCart 上下文对象 cart1cart2,并分别在构造函数中传入不同的具体策略对象,这样 cart1 初始使用满减策略,cart2 使用固定折扣策略。然后通过调用 calculateFinalPrice 方法分别计算并展示了商品价格为300时,不同策略下的最终价格。
    • 之后又通过 cart1setDiscountStrategy 方法将其使用的策略更换为固定折扣策略,并再次计算和展示了最终价格,体现了策略模式可以在运行时灵活切换算法(策略)的特点。

通过这个示例可以看到,策略模式将不同的折扣算法封装在各自的具体策略类中,而 ShoppingCart 上下文类只需要关心抽象策略接口,根据具体情况使用不同的具体策略来计算最终价格,使得代码结构清晰,易于扩展和维护。例如,如果后续要添加一个新的折扣策略(如会员专享折扣策略等),只需要创建一个新的具体策略类实现 DiscountStrategy 接口,并在需要的地方(如 ShoppingCart 上下文对象中)使用这个新策略即可,不需要修改原有的核心代码逻辑。

相关文章:

重温设计模式--13、策略模式

策略模式介绍 文章目录 策略模式介绍C 代码示例 策略模式是一种行为设计模式&#xff0c;它允许在运行时选择算法的行为。该模式将算法的定义和使用分离开来&#xff0c;使得算法可以独立于使用它的客户端而变化&#xff0c;提高了代码的灵活性和可维护性。 其主要包含以下几个…...

【Rust自学】10.7. 生命周期 Pt.3:输入输出生命周期与3规则

喜欢的话别忘了点赞、收藏加关注哦&#xff08;加关注即可阅读全文&#xff09;&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 10.7.1. 深入理解生命周期 1.指定生命周期参数的方式依赖于函数所做的事情 以上一篇文章的…...

产品经理-竞品分析

竞品分析是企业制定战略和产品优化的关键步骤&#xff0c;通过深入分析竞争对手的产品与策略&#xff0c;企业可以更好地定位自己并寻找改进的方向。这篇文章详细阐述了进行有效竞品分析的五个关键步骤&#xff0c;帮助产品经理精准掌握竞争态势&#xff0c;从而在市场中占据有…...

51单片机——8*8LED点阵

LED 点阵的行则为发光二极管的阳极&#xff0c;LED 点阵的列则为发光二极管的阴极 根据 LED 发光二极管导通原理&#xff0c;当阳极为高电平&#xff0c;阴极为低电平则点亮&#xff0c;否则熄灭。 因此通过单片机P0口可控制点阵列&#xff0c;74HC595可控制点阵行 11 脚 SR…...

力扣第136题:只出现一次的数字 巧用异或

力扣第136题&#xff1a;只出现一次的数字 C语言解法 题目描述 给定一个非空的整数数组 nums &#xff0c;其中除一个元素只出现一次外&#xff0c;其他每个元素均出现两次。找出那个只出现一次的元素。 示例 示例 1: 输入: nums [2,2,1] 输出: 1示例 2: 输入: nums [4…...

TCP 如何获取端口信息

注&#xff1a;本文为 “TCP 如何获取端口信息” 相关讨论摘录。 机翻&#xff0c;未校。 How TCP Gets Port Information TCP 如何获取端口信息 asked Nov 10, 2024 at 19:57 user15503745 API Call for Connection API 调用以建立连接 Before the app can send data d…...

RabbitMQ发布确认高级篇(RabbitMQ Release Confirmation Advanced Edition)

系统学习消息队列——RabbitMQ的发布确认高级篇 简介 ‌RabbitMQ是一个开源的消息代理软件&#xff0c;实现了‌高级消息队列协议&#xff08;AMQP&#xff09;‌&#xff0c;主要用于在分布式系统中进行消息传递。RabbitMQ由‌‌Erlang语言编写&#xff0c;具有高性能、健壮…...

福建省乡镇界面数据arcgis格式shp乡镇名称和编码无偏移坐标内容测评

【标题解析】 标题"最新福建省乡镇界面数据arcgis格式shp乡镇名称和编码无偏移坐标"揭示了几个关键信息。这是关于福建省乡镇级别的地理数据&#xff0c;它包含乡镇的边界信息。这些数据是以ArcGIS兼容的SHP&#xff08;Shapefile&#xff09;格式存储的&#xff0c;…...

Kafka 消费者

Kafka消费者主要负责消费&#xff08;读取和处理&#xff09;由生产者发布的消息。 1 消费者入门 消费组将具有相同group.id的消费者实例组织成组。它们共同读取一个或多个主题的消息。每个消费者都有一个对应的消费组。 消息发布到主题后&#xff0c;只会被投递给订阅它的每…...

人形机器人当前现状与挑战:从技术突破到未来发展

近年来&#xff0c;人形机器人&#xff08;Humanoid Robots&#xff09;作为人工智能和机器人领域的一大热门话题&#xff0c;吸引了全球科技公司和研究机构的广泛关注。尤其是在日本、美国、欧洲等技术领先的地区&#xff0c;人形机器人的研究与发展日益繁荣&#xff0c;从早期…...

6 网络编程

基本概念扫盲 为什么需要计算机网络 如下图所示,A、B、C三个不同地域的主机要想进行通信不是凭空就可以通信的,而是需要基于互联网进行互相连接、通信。 为什么需要协议 如下图所示,红和蓝是联合攻打绿,它们以烽火为信号出动攻打绿,那么这时候就需要一个约定,比如红先…...

智能边缘计算:开启智能新时代

什么是智能边缘计算&#xff1f; 在当今数字化浪潮中&#xff0c;边缘计算已成为一个热门词汇。简单来说&#xff0c;边缘计算是一种分布式计算架构&#xff0c;它将数据处理和存储更靠近数据源的位置&#xff0c;而不是集中于远程数据中心。通过这种方式&#xff0c;边缘计算…...

AI投资分析:用于股票评级的大型语言模型(LLMs)

“AI in Investment Analysis: LLMs for Equity Stock Ratings” 论文地址&#xff1a;https://arxiv.org/pdf/2411.00856 摘要 投资分析作为金融服务领域的重要组成部分&#xff0c;LLMs&#xff08;大型语言模型&#xff09;为股票评级带来了改进的潜力。传统的股票评级方式…...

初始SpringBoot:详解特性和结构

??JAVA码农探花&#xff1a; ?? 推荐专栏&#xff1a;《SSM笔记》《SpringBoot笔记》 ??学无止境&#xff0c;不骄不躁&#xff0c;知行合一 目录 前言 一、SpringBoot项目结构 1.启动类的位置 2.pom文件 start parent 打包 二、依赖管理特性 三、自动配置特性…...

【计算机网络】深入解析OSI和TCP/IP模型:网络请求的底层处理过程

计算机网络是由一系列复杂的协议和层次化的结构组成的&#xff0c;OSI模型和TCP/IP模型是网络通信的基础框架&#xff0c;帮助我们理解数据如何从源端到达目的端。在这篇文章中&#xff0c;我将通过深入分析每一层的功能和具体处理流程&#xff0c;帮助你更加详细地理解网络请求…...

快速学习 pytest 基础知识

全篇大概 5000 字&#xff08;含代码&#xff09;&#xff0c;建议阅读时间10min 简介 Pytest是一个非常成熟的测试框架&#xff0c;适用于但愿测试、UI测试、接口测试。 简单灵活、上手快支持参数化具有多个第三方插件可以直接使用 assert 进行断言 一、Pytest安装 pip inst…...

Ae:合成设置 - 3D 渲染器

Ae菜单&#xff1a;合成/合成设置 Composition/Composition Settings 快捷键&#xff1a;Ctrl K After Effects “合成设置”对话框中的3D 渲染器 3D Renderer选项卡用于选择和配置合成的 3D 渲染器类型&#xff0c;所选渲染器决定了合成中的 3D 图层可以使用的功能&#xff0…...

java异步判断线程池所有任务是否执行完

在Java中&#xff0c;使用线程池&#xff08;ExecutorService&#xff09;可以高效地管理和执行异步任务。对于某些应用场景&#xff0c;可能需要异步地判断线程池中所有任务是否执行完毕。以下是一个高度专业的指南&#xff0c;讲解如何在Java中实现这一功能。 步骤概述 创建…...

25.1.3 UART串口通信

1.FSMP1A开发板进行串口通信实验&#xff1a; 功能&#xff1a;电脑输入LED_ON点亮扩展版LED灯&#xff0c;输入LED_OFF熄灭扩展版LED灯 代码实现&#xff1a; uart4.c #include "uart4.h" //串口初始化 void uart4_init(){//使能UART4外设时钟RCC->MP_APB1ENSE…...

如何使用脚手架工具开始,快速搭建一个 Express 项目的基础架构

前言 将从如何使用脚手架工具开始&#xff0c;快速搭建一个 Express 项目的基础架构。接着&#xff0c;文章将详细讲解 Express 中间件的概念、分类以及如何有效地使用中间件来增强应用的功能和性能。最后&#xff0c;我们将讨论如何制定合理的接口规范&#xff0c;以确保 API …...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...