C++设计模式行为模式———策略模式
文章目录
- 一、引言
- 二、策略模式
- 三、总结
一、引言
策略模式是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。与模板方法模式类似,都是以扩展的方式来支持未来的变化。
策略模式需要我们定义一系列的算法,并且将每种算法都放入到独立的类中,在实际操作的时候使这些算法对象可以相互替换。
二、策略模式
使用闯关打斗游戏为例,当主角走到某个特定的场景位置或者击杀某个大型怪物后,这些道具就会出现,主角通过走到该道具上就可以实现为自身补充生命值的目的。前期主要规划了3个道具(药品):
- 补血丹可以补充200点生命值。
- 大还丹可以补充300点生命值。
- 守护丹可以补充500点生命值。
首先创建出几种战士类型,都继承于Fighter。
class Fighter {
public:Fighter(int life, int magic, int attack):m_life(life) {}virtual ~Fighter() {}void setLife(int life) { m_life = life; }int getLife() { return m_life; }
private:int m_life;//生命值
};
//"战士"类,父类为Fighter
class F_Warrior :public Fighter {
public:F_Warrior(int life, int magic, int attack) :Fighter(life, magic, attack) {}
};
//"法师"类,父类为Fighter
class F_Mage :public Fighter {
public:F_Mage(int life, int magic, int attack) :Fighter(life, magic, attack) {}
};
我们设置一个枚举类型来表示三种加血道具,同时给Fighter增加补血函数:
enum class ItemAddlife
{LF_BXD, LF_DHD, LF_SHD
};
void Fighter::UseItem(ItemAddlife type)
{switch (type){case ItemAddlife::LF_BXD:m_life += 200;break;case ItemAddlife::LF_DHD:m_life += 300;break;case ItemAddlife::LF_SHD:m_life += 500;break;default:break;}
}
此时如果要加血的话,我们的战士子类或法师子类直接调用useItem函数即可,但是要增加新的枚举类型,也要在UseItem中的switch语句中增加判断条件,这不符合开闭原则,而且一旦条件特别多,对程序的运行效率和可维护性会造成影响。
下面使用策略模式对上述代码进行改进,在策略模式中,可以把UseItem成员函数中的每个条件分支中的代码(也称“算法”)写到一个个类中,那么每个封装了算法的类就可以称为一种策略(类不仅可以表示一种存在于真实世界的东西,也可以表示一种不存在于真实世界的东西),当然,应该为这些策略抽象出一个统一的父类以便实现多态:
class ItemStrategy
{
public:virtual void UseItem(Fighter* mainobj) = 0;virtual ~ItemStrategy() {}
};
//补血丹策略类
class ItemStrategy_BxD :public ItemStrategy {
public:virtual void UseItem(Fighter* mainobj) override{mainobj->setLife(mainobj->getLife() + 200);//补充200点生命值}};
//大还丹策略类
class ItemStrategy_DHD :public ItemStrategy {
public:virtual void UseItem(Fighter* mainobj) {mainobj->setLife(mainobj->getLife() + 300);//补充300点生命值}
};
//守护丹策略类
class ItemStrategy_SHD :public ItemStrategy
{
public:virtual void UseItem(Fighter* mainobj) {mainobj->setLife(mainobj->getLife() + 500);//补充500点生命值}
};
从上面的代码中可以看到,UseItem成员函数直接使用了Fighter* 作为形参,意图是把主角所有必要的信息都传递到策略类中来,让策略类中的UseItem成员函数在需要时可以随时回调Fighter中的各种成员函数。下面我们修改Fighter:
class Fighter {
public:Fighter(int life):m_life(life) {}void UseItem(ItemStrategy* type);void setLife(int life) { m_life = life; }int getLife() { return m_life; }void setItemStrategy(ItemStrategy* star) {type = star;}virtual ~Fighter() {}
private:ItemStrategy* type;int m_life;//生命值
};
void Fighter::UseItem(ItemStrategy* type)
{type->UseItem(this);
}
如上,将算法(使用道具增加生命值这件事)本身独立到ItemStrategy的各个子类中,而不在Fighter类中实现。当增加新的道具时,只需要增加一个新的策略子类即可,这样就符合开闭原则了。
Fighter类与ItemStrategy类相互作用实现指定的算法,当算法被调用时,Fighter将算法需要的所有数据(这里其实是Fighter类对象自身)传递给ItemStrategy,当然如果算法需要的数据比较少,则可以仅仅传递必需的数据(而不必将Fighter类对象本身传递给算法)。

策略模式一般有三种角色:
- 上下文类(Context)是使用算法的角色,该类中维持着一个对抽象策略类的指针或引用。这里指
Fighter类。 - 抽象策略类(Strategy):定义义所支持的算法的公共接口,是所有策略类的父类。这里指
ItemStrategy类。 - 具体策略类(ConcreteStrategy):抽象策略类的子类,实现抽象策略类中声明的接口。这里指
ItemStrategy_BXD、ItemStrategy_DHD、ItemStrategy_SHD类。
策略模式结构

引人策略设计模式的定义:定义一系列算法类(策略类),将每个算法封装起来,让它们可以相互替换。换句话说,策略模式通常把一系列算法封装到一系列具体策略类中作为抽象策略类的子类,然后根据实际需要使用这些子类。
假如你需要前往机场。 你可以选择乘坐公共汽车、 预约出租车或骑自行车。 这些就是你的出行策略。 你可以根据预算或时间等因素来选择其中一种策略。
三、总结
策略模式中的若干个策略对象相互之间是完全独立的, 它们不知道其他对象的存在。当我们想使用对象中各种不同的算法变体,并希望能够在运行的时候切换这些算法时,可以选择使用策略模式来处理这个问题。
以往利用增加新的f条件分支来支持新算法的方式违背了开闭原则,引人策略模式后,通过增加新的策略子类实现了对开闭原则的完全支持,也就是以扩展的方式支持未来的变化。所以,如果读者今后在编写代码时遇到有多个if条件分支或者switch分支的语句,并且这些分支并不稳定,会经常改动时,则率先考虑能否通过引入策略模式加以解决,所以很多情况下,策略模式是if或者switch条件分支的取代者。
装饰模式可让你更改对象的外表, 策略则让你能够改变其本质。
模板方法模式基于继承机制: 它允许你通过扩展子类中的部分内容来改变部分算法。 策略基于组合机制: 你可以通过对相应行为提供不同的策略来改变对象的部分行为。 模板方法在类层次上运作, 因此它是静态的。 策略在对象层次上运作, 因此允许在运行时切换行为。
装饰模式可让你更改对象的外表, 策略则让你能够改变其本质。
模板方法模式基于继承机制: 它允许你通过扩展子类中的部分内容来改变部分算法。 策略基于组合机制: 你可以通过对相应行为提供不同的策略来改变对象的部分行为。 模板方法在类层次上运作, 因此它是静态的。 策略在对象层次上运作, 因此允许在运行时切换行为。
同时,状态模式可被视为策略模式的扩展。 两者都基于组合机制: 它们都通过将部分工作委派给 “帮手” 对象来改变其在不同情景下的行为。 策略使得这些对象相互之间完全独立, 它们不知道其他对象的存在。 但状态模式没有限制具体状态之间的依赖, 且允许它们自行改变在不同情景下的状态。
相关文章:
C++设计模式行为模式———策略模式
文章目录 一、引言二、策略模式三、总结 一、引言 策略模式是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。与模板方法模式类似,都是以扩展的方式来支持未来的变化。…...
Spring Cloud 中 bootstrap.yml 配置文件详解
Spring Cloud 中 bootstrap.yml 配置文件详解 1. 什么是 bootstrap.yml? bootstrap.yml 是 Spring Cloud 提供的一个特殊配置文件,主要用于初始化 Spring Cloud 应用程序的环境。与常见的 application.yml 不同,bootstrap.yml 在 Spring 应用…...
Java项目实战II基于SpringBoot前后端分离的网吧管理系统(开发文档+数据库+源码)
目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着互联网技术的不断发展…...
ASP网络安全讲述
一 前言 Microsoft Active Server Pages(ASP)是服务器端脚本编写环境,使用它可以创建和运行动态、交互的 Web 服务器应用程序。使用 ASP 可以组合 HTML 页 、脚本命令和 ActiveX 组件以创建交互的 Web 页和基于 Web 的功能强大的应用程序…...
DFS 创建分级菜单
菜单级别不确定,想要自适应,且可以折叠的菜单。 数据是一个数组。 <template><div class"Level" ref"Level"></div> </template>import {ref} from vue export default{data(){Level:ref(null),menuData…...
HDU Go Running(最小点覆盖 + 网络流优化)
题目大意:有一条无限长跑道,每个人可以规定自己跑步的方向,起点,跑步起止时间。每个人跑步的速度都是1m/s。最后从监控人员哪里得到了n个报告,每个报告给出了某人在某一时候所在的位置,问跑步的最少可能人数…...
C++设计模式-中介者模式
动机(Motivation) 多个对象相互关联的情况,对象之间常常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将面临不断的变化。在这种情况下,可以使用一种”中介对象“来管理对象间的关联关系,避免…...
文件上传与下载服务 | Flask 实战
之前介绍了 droppy 文件共享服务的搭建。但在一些场景中,我们需要在命令行或在 Python 代码中,临时上传和下载文件。这时可以用一个更简单的策略:使用 flask 编写一个临时的 API。 服务端配置 以下是一个简单的 Flask 应用程序代码示例&…...
MySQL 中的排序:索引排序与文件排序
文章目录 MySQL 中的排序:索引排序与文件排序全解析一、引言二、索引排序(一)原理(二)示例 三、文件排序(一)单路排序(二)双路排序(三)归并排序 四…...
深入理解React Hooks:使用useState和useEffect
引言 React Hooks是React 16.8引入的一项强大功能,它使函数组件能够使用状态和其他React特性。本文将深入探讨两个最常用的Hooks:useState和useEffect,并通过实际代码示例展示它们的使用方法。 1. 什么是React Hooks? React Ho…...
AWS codebuild + jenkins + github 实践CI/CD
前文 本文使用 Jenkins 结合 CodeBuild, CodeDeploy 实现 Serverless 的 CI/CD 工作流,用于自动化发布已经部署 lambda 函数。 在 AWS 海外区,CI/CD 工作流可以用 codepipeline 这项产品来方便的实现, CICD 基本概念 持续集成( Continuous…...
Android PMS(Package Manager Service)源码介绍
文章目录 前言一、PMS 启动流程二、APK 安装流程三、APK 卸载流程四、权限管理静态权限动态权限 五、 数据存储与一致性六、 PMS 的安全性策略1、权限检查2、签名认证3、动态权限管理4、应用安装验证5、保护系统目录 七、PMS 调试方法总结 前言 PackageManagerService…...
运维面试整理总结
面试题可以参考:面试题总结 查看系统相关信息 查看系统登陆成功与失败记录 成功:last失败:lastb 查看二进制文件 hexdump查看进程端口或连接 netstat -nltp ss -nltp补充:pidof与lsof命令 pidof [进程名] #根据 进程名 查询进程id ls…...
图数据库 Cypher语言
图数据库 属性图 属性图(Property Graph)概述 属性图是一种广泛用于建模关系数据的图数据结构,它将**顶点(节点)和边(关系)**进行结构化存储,并为它们附加属性以提供丰富的语义信…...
阿里云oss转发上线-实现不出网钓鱼
本地实现阿里云oss转发上线,全部代码在文末,代码存在冗余 实战环境 被钓鱼机器不出网只可访问内部网络包含集团oss 实战思路 若将我们的shellcode文件上传到集团oss上仍无法上线,那么就利用oss做中转使用本地转发进行上线,先发送…...
Spring Boot 3.4.0 发行:革新与突破的里程碑
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…...
【网络安全】
黑客入侵 什么是黑客入侵? “黑客”是一个外来词,是英语单词hacker的中文音译。最初,“黑客”只是一个褒义词,指的是那些尽力挖掘计算机程序最大潜力的点脑精英,他们讨论软件黑客的技巧和态度,以及共享文化…...
在SQLyog中导入和导出数据库
导入 假如我要导入一个xxx.sql,我就先创建一个叫做xxx的数据库。 然后右键点击导入、执行SQL脚本 选择要导入的数据库文件的位置,点击执行即可 注意: 导入之后记得刷新一下导出 选择你要导出的数据库 右键选择:备份/导出、…...
RabbitMQ简单应用
概念 RabbitMQ 是一种流行的开源消息代理(Message Broker)软件,它实现了高级消息队列协议(AMQP - Advanced Message Queuing Protocol)。RabbitMQ 通过高效的消息传递机制,主要应用于分布式系统中解耦应用…...
使用LUKS对Linux磁盘进行加密
前言 本实验用于日常学习用,如需对存有重要数据的磁盘进行操作,请做好数据备份工作。 此实验只是使用LUKS工具的冰山一角,后续还会有更多功能等待探索。 LUKS(Linux Unified Key Setup)是Linux系统中用于磁盘加密的一…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
