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系统中用于磁盘加密的一…...
遥感智能解译新纪元:GeoSeg破解地物识别效率瓶颈的技术革新
遥感智能解译新纪元:GeoSeg破解地物识别效率瓶颈的技术革新 【免费下载链接】GeoSeg UNetFormer: A UNet-like transformer for efficient semantic segmentation of remote sensing urban scene imagery, ISPRS. Also, including other vision transformers and CN…...
4个强大的开源工具功能扩展方案
4个强大的开源工具功能扩展方案 【免费下载链接】cursor-free-vip [Support 0.45](Multi Language 多语言)自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro 功能: Youve reached your trial request limit. / Too many fre…...
CHORD-X从零开始:C语言基础概念学习报告自动生成教程
CHORD-X从零开始:C语言基础概念学习报告自动生成教程 你是不是也遇到过这样的烦恼?作为编程老师,每次讲完C语言的指针、结构体这些难点,总想给学生一份清晰易懂的复习报告,但自己动手整理又太花时间。或者,…...
【Matlab】MATLAB教程:数据插值interp1(案例:interp1(x,y,xi,‘linear‘);应用:数据补全、插值)
MATLAB教程:数据插值interp1(案例:interp1(x,y,xi,linear);应用:数据补全、插值) 在科研实验、工程监测、信号采集等各类数据获取场景中,受限于设备精度、测试条件、环境干扰等因素,采集到的原始数据往往存在**数据点稀疏、采样间隔不均、局部数据缺失**等问题,直接使…...
XML Notepad:免费高效的XML编辑器终极指南
XML Notepad:免费高效的XML编辑器终极指南 【免费下载链接】XmlNotepad XML Notepad provides a simple intuitive User Interface for browsing and editing XML documents. 项目地址: https://gitcode.com/gh_mirrors/xm/XmlNotepad XML Notepad是一款由微…...
ArcGIS Pro模型构建器实战:从零搭建自动化地理处理工作流
1. 初识ArcGIS Pro模型构建器 第一次接触ArcGIS Pro的模型构建器时,我完全被它的可视化操作界面惊艳到了。这就像搭积木一样,不需要写一行代码,就能把复杂的地理处理流程串起来。记得当时有个项目需要批量处理上百个乡镇的耕地数据࿰…...
Undecimus革新性全流程越狱技术指南:从核心价值到实用工具
Undecimus革新性全流程越狱技术指南:从核心价值到实用工具 【免费下载链接】Undecimus unc0ver jailbreak for iOS 11.0 - 12.4 项目地址: https://gitcode.com/gh_mirrors/un/Undecimus 一、核心价值:破解iOS生态三大痛点 Undecimus作为针对iOS…...
利用快马平台十分钟搭建树莓派环境监测系统原型
今天想和大家分享一个快速搭建树莓派环境监测系统的小实验。作为一个硬件爱好者,我经常用树莓派做各种物联网原型开发,但每次从零开始配置环境、写基础代码都很耗时。最近发现InsCode(快马)平台能帮我省去很多重复工作,特别适合快速验证想法。…...
Agent 性能优化:降低 Token 消耗的 5 个技巧
Agent 性能优化:降低 Token 消耗的 5 个技巧系列文章: 《AI Agent 开发实战》第 7 期 难度等级: ⭐⭐⭐⭐ 预计耗时: 35 分钟🎯 本文目标 学会优化 AI Agent 性能: ✅ 减少 Token 消耗✅ 提高响应速度✅ 降…...
[DRAM Test]从入门到精通:全面解析DRAM内存测试工具与实战故障排查
1. DRAM测试工具全景解析 内存作为计算机系统的核心组件,其稳定性直接影响整机性能。我经手过的蓝屏案例中,超过60%最终都指向内存问题。目前市面上的DRAM测试工具主要分为三大类: 应用层工具以HCI MemTest为代表,这类工具运行在操…...
