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

C++设计模式_行为型模式_策略模式Strategy

策略模式是一种行为型模式,其实现过程与模板方法模式非常类似,都是通过以扩展的方式支持未来的变化。

一个具体实现范例的逐步重构

场景:主角要补充血量,现在要设置三种补血的药丸,分别是补血丹,补充200点生命值,大还丹,补充300生命值,守护丹:补充500点生命值;
创建fighter.h,在其中创建Fighter类—战斗者父类,然后实现战士类和法师类,继承自战斗者父类。

enum class ItemMedicine
{LIFE_BXD, // 补血丹LIFE_DHD, // 大还丹LIFE_SHD, // 守护丹
};class Fighter
{
public:Fighter(int life, int magic, int attack) :m_life(life), m_magic(magic), m_attack(attack) {}// 定义一个吃药的函数// 这个函数的参数是一个枚举类型,这个枚举类型定义了各种各样的药品,比如补血丹、大还丹、守护丹等等。void useItem(ItemMedicine type){if (type == ItemMedicine::LIFE_BXD) //道具类型:补血丹{m_life += 200;//补充200点生命值cout << "补充了补血丹" << endl;}else if (type == ItemMedicine::LIFE_DHD) //道具类型:大还丹{m_life += 300;//补充300点生命值cout << "补充了大还丹" << endl;}else if (type == ItemMedicine::LIFE_SHD) //道具类型:守护丹{m_life += 500;//补充500点生命值cout << "补充了守护丹" << endl;}//.......其他的一些判断逻辑,略。。。。。。}protected:int m_life;int m_magic;int m_attack;
};class F_Warrior :public Fighter
{
public:F_Warrior(int life, int magic, int attack) :Fighter(life, magic, attack) {}};;class F_Mage : public Fighter
{
public:F_Mage(int life, int magic, int attack) :Fighter(life, magic, attack) {}private:};

上面代码缺点:
如果要增加新的道具,比如 补魔法丹,那么就要在Fighter类中UseItem函数中,增加if else语句,这样就违背了开闭原则—对扩展开放,对修改关闭。
如果怪物也要吃补充生命值的药物,那么就要在Monster类中也增加UseItem函数,这样就违反了单一职责原则,这属于代码级别的重复。
如果主角吃药后,还有其他的一些额外的逻辑,比如吃药后从中毒状态变为正常状态,还要在useItem函数中增加判断语句;同样,如果主角处于狂暴状态,血量要额外增加。这样也 违反的开闭原则。
比如实现吃药后主角从中毒变为正常,需要修改如下:

	void useItem(ItemMedicine type){if (type == ItemMedicine::LIFE_BXD) //道具类型:补血丹{m_life += 200;//补充200点生命值cout << "补充了补血丹" << endl;// if (主角中毒){// 停止中毒状态,也就是主角吃药后不再中毒}if (主角处于狂暴状态){m_life += 400; //额外再补充400点生命值m_magic += 200; //魔法值也再补充200点}}else if (type == ItemMedicine::LIFE_DHD) //道具类型:大还丹{m_life += 300;//补充300点生命值cout << "补充了大还丹" << endl;}else if (type == ItemMedicine::LIFE_SHD) //道具类型:守护丹{m_life += 500;//补充500点生命值cout << "补充了守护丹" << endl;}//.......其他的一些判断逻辑,略。。。。。。}

使用策略模式对代码重构

策略模式的定义:定义一系列算法(策略类),将每个算法封装起来,让它们可以相互替换。换句话说,策略模式通常把一系列算法(函数)封装到一系列具体策略类中来作为抽象策略类的子类,然后根据实际需要使用这些子类。
策略类中三种角色:
环境类:上面代码中的Fighter类,该类中维持着一个对抽象策略类的指针或引用。
抽象策略类:定义所支持的算法的公共接口,是所有策略类的父类,这里指ItemStrategy
具体策略类:抽象策略类子类,实现抽象策略类中声明的接口,这里指ItemStrategy_BXD ItemStrategy_HHD;

    class Fighter;class ItemStrategy{public:virtual void useItem(Fighter* Fighter) = 0;virtual ~ItemStrategy(){}protected:Fighter* m_pFighter = nullptr;};class ItemStrategy_BXD : public ItemStrategy{public:void useItem(Fighter* fighter) override; // 声明,稍后定义};class ItemStrategy_HHD : public ItemStrategy{public:void useItem(Fighter* fighter) override; // 声明,稍后定义};class Fighter{public:Fighter() {}Fighter(int life, int magic, int attack) :m_life(life), m_magic(magic), m_attack(attack) {}virtual  ~Fighter() {}public:void SetLift(int life){m_life = life;}int  GetLife(){return m_life;}void SetItemStrategy(ItemStrategy* itemStrategy){m_itemStrategy = itemStrategy;}void UsetItem(){m_itemStrategy->useItem(this);}protected:int m_life;int m_attack;int m_magic;ItemStrategy* m_itemStrategy = nullptr;};// 战士类class Warrior : public Fighter{public:using Fighter::Fighter;};// 将实现放到 Fighter 定义之后inline void ItemStrategy_BXD::useItem(Fighter* fighter){fighter->SetLift(fighter->GetLife() + 100);}inline void ItemStrategy_HHD::useItem(Fighter* fighter){fighter->SetLift(fighter->GetLife() + 80);}void test(){Fighter* fighter = new Warrior(100, 20, 300);// 实例化一个对象ItemStrategy* ItemStrategy = new ItemStrategy_BXD();fighter->SetItemStrategy(ItemStrategy);fighter->UsetItem();}

策略类优点:
1 以扩展的方式支持对未来的变化,符合开闭原则。遇到大量不稳定的if条件分支 或者switch分支,就要优先考虑是否可以通过策略模式来解决。策略模式是if,switch条件分支的杀手。
2 算法可以被复用。
3 策略模式可以看成是类继承的一种替代方案。通过为环境类对象指定不同的策略,就可以改变环境类对象的行为。比如,战士对象吃大还丹。
策略类的缺点:
1 导致引入许多新策略类;
2 使用策略时,调用者(main主函数)必须熟知所有策略类的功能并根据实际需要自行决定使用哪个策略类。
UML图:
在这里插入图片描述
组合关系:Gighter中有straty类的指针。

依赖倒置原则

依赖倒置原则:Dependency Inversion Principle 简称DIP,是面向独享设计的主要实现方法,同时也是实现开闭原则的重要实现途径。
解释:高层组建不应该依赖于底层组建,比如之前的主角(战士,法师)类就是高层组建,怪物类(亡灵类,机械类等)就是底层组建,高层组建不能直接依赖于底层组建,举例:

namespace _nmsp1
{class M_Undead{public:void getinfo(){cout << "M_Undead" << endl;}};class M_Element{public:void getinfo(){cout << "M_Element" << endl;}};class M_Mechnical{public:void getinfo(){cout << "M_Mechnical" << endl;}};// 战士主角class Fighter_Warrior{public:// 攻击一种怪物,对应增加一个攻击怪物的函数void attack_enemy_undead(M_Undead *p){cout << "attack_enemy" << endl;}void attack_enemy_mechnical(M_Mechnical* p){cout << "M_Mechnical" << endl;}};
}
int main()
{// 创建一个高层类_nmsp1::Fighter_Warrior *pWar = new _nmsp1::Fighter_Warrior();// 创建一个低层类_nmsp1::M_Undead* p1 = new _nmsp1::M_Undead();// 调用高层类的函数 实现攻击怪物目的pWar->attack_enemy_undead(p1);// 战士继续攻击另外一种怪物_nmsp1::M_Mechnical* p2 = new _nmsp1::M_Mechnical();pWar->attack_enemy_mechnical(p2);return 0;
}

在这里插入图片描述
从上图可以看出,高层组建依赖于底层组建。
改进:
要实现高层组建和底层组建的解耦合,只需要增加一个Monster 类,代码如下:

namespace _nmsp2
{class Monster{public:Monster() {}virtual ~Monster(){}};class M_Undead : public Monster{public:void getinfo(){cout << "M_Undead" << endl;}};class M_Element : public Monster{public:void getinfo(){cout << "M_Element" << endl;}};class M_Mechnical : public Monster{public:void getinfo(){cout << "M_Mechnical" << endl;}};// 战士主角class Fighter_Warrior{public:// 攻击一种怪物,对应增加一个攻击怪物的函数void attack_enemy(Monster* p){cout << "attack_enemy" << endl;}};
}int main()
{_nmsp2::Fighter_Warrior *pWar2 = new _nmsp2::Fighter_Warrior();// 亡灵类怪物_nmsp2::Monster* p1 = new _nmsp2::M_Undead();pWar2->attack_enemy(p1);// 攻击亡灵类_nmsp2::Monster* p2 = new _nmsp2::M_Mechnical();pWar2->attack_enemy(p2);// 攻击亡灵类return 0;
}

在这里插入图片描述

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

相关文章:

  • **发散创新:多智能体系统的探索与实践**随着人工智能技术的飞速发展,多智能体系统作为当今研究的热点领域,正受到越来越多关注
  • 音乐网站设计企业网络搭建与应用
  • Flink Data Sink 理论 、架构、语义保证、两阶段提交与可插拔拓扑
  • DeviceNet转Ethernet/IP食品饮料包装线码垛机器人高效通信方案
  • 《基于分布式多模态传感模块的全身尺度机器人皮肤:设计、评估与应用》TR-O 2025论文解析
  • 亿万网站网站开发详细流程
  • 还是网站好买一个app软件要多少钱
  • 无锡万度网站建设WordPress Demo演示
  • 智能外呼是什么意思
  • 【读论文】——基于光谱学的玉米种子品质检测及其成像技术综述
  • 如何自建网站满分作文网
  • 服务器/Pytorch——对于只调用一次的函数初始化,放在for训练外面和里面的差异
  • iOS 混淆与 IPA 加固一页式行动手册(多工具组合实战 源码成品运维闭环)
  • PySide6 使用搜索引擎搜索 多类实现 更新1次
  • 宁波网站优化的关键企业网站后台管理系统模板
  • 网站开发项目需求分析说明书电子商务网站开发与实现
  • 群晖实现证书90天自动更新(无需对外提供80端口)
  • AMCL自适应(KLD - Sampling: Adaptive Particle Filters)一种基于粒子滤波的移动机器人定位算法
  • NOR FLASH
  • 网站代码优化方案网站建设和编程的区别
  • 重庆建设工程造价管理协会网站直播网站开发价格
  • 【Nest】集成测试
  • ELK运维之路(Logstash基础使用-7.17.24)
  • 快速排序(JAVA详细讲解快速排序的四种方式)
  • 数据结构四大简单排序算法详解:直接插入排序、选择排序、基数排序和冒泡排序
  • 官渡网站建设wordpress单页面制作
  • 企业电子商务网站开发数据库设计昆明seo博客
  • 东道 网站建设erp系统哪家做得好
  • 现代 Web 开发中检测用户离开页面的完整方案(附 Vue 实现)
  • [crackme]029-figugegl.1