C++ 设计模式——状态模式

devtools/2024/10/19 21:31:47/

C++ 设计模式——状态模式

C++ 设计模式——状态模式

状态模式(State Pattern)是一种行为型设计模式,它允许对象在其内部状态发生变化时,动态地改变其行为。该模式的核心在于将状态相关的行为封装到独立的状态类中,使得对象的行为随状态而变化,从而减少冗余的条件判断。

1. 主要组成成分

  1. 上下文(Context):持有一个状态对象的引用,负责与客户端交互,并将请求委托给当前状态对象。
  2. 状态接口(State):定义了所有具体状态类的公共接口。
  3. 具体状态(Concrete State):实现了状态接口,封装了与特定状态相关的行为。

2. 逐步构建状态模式

以下是一个简单的状态模式示例,模拟一个怪物的状态变化。

1. 状态接口定义
  • MonsterStatus 是一个抽象类,定义了所有具体状态类必须实现的接口。
  • Attacked 方法用于处理怪物被攻击的逻辑,接受攻击力和怪物对象的引用。
//怪物状态类的父类
class MonsterStatus
{
public:virtual void Attacked(int power, Monster* mainobj) = 0;virtual ~MonsterStatus() {}
};
2. 具体状态类实现
  • 每个状态类继承自 MonsterStatus,并实现 Attacked 方法。
  • 使用单例模式以确保每种状态只有一个实例,减少内存开销。
//凶悍状态类
class MonsterStatus_Feroc :public MonsterStatus
{
public:virtual void Attacked(int power, Monster* mainobj);public:static MonsterStatus_Feroc* getInstance(){static MonsterStatus_Feroc instance;return &instance;}};//不安状态类
class MonsterStatus_Worr :public MonsterStatus
{
public:virtual void Attacked(int power, Monster* mainobj);public:static MonsterStatus_Worr* getInstance(){static MonsterStatus_Worr instance;return &instance;}};//恐惧状态类
class MonsterStatus_Fear :public MonsterStatus
{
public:virtual void Attacked(int power, Monster* mainobj);public:static MonsterStatus_Fear* getInstance(){static MonsterStatus_Fear instance;return &instance;}};//死亡状态类
class MonsterStatus_Dead :public MonsterStatus
{
public:virtual void Attacked(int power, Monster* mainobj);public:static MonsterStatus_Dead* getInstance(){static MonsterStatus_Dead instance;return &instance;}};
3. 上下文类的实现
  • Monster 类作为上下文类,持有当前状态的引用。
  • checkAndSwitchState 方法用于根据当前生命值判断并切换状态。
  • Attacked 方法调用当前状态的 Attacked 方法。
//怪物类
class Monster
{
public:Monster(int life);~Monster();public:void Attacked(int power);  //怪物被攻击public:int GetLife() //获取怪物血量{return m_life;}void SetLife(int life) //设置怪物血量{m_life = life;}MonsterStatus* getCurrentState() //获取怪物当前状态{return m_pState;}void setCurrentState(MonsterStatus* pstate) //设置怪物当前状态{m_pState = pstate;}private:int            m_life;    //血量(生命值)MonsterStatus* m_pState;  //持有状态对象
};
4. 主函数
int main()
{Monster monster(500);cout << "怪物出生,当前处于凶悍状态,500点血!" << endl;monster.Attacked(20);monster.Attacked(100);monster.Attacked(200);monster.Attacked(170);monster.Attacked(100);monster.Attacked(100);return 0;
}

3. 状态模式 UML 图

<a class=状态模式 UML 图" />

状态模式 UML 图解析
  • Context(环境类):也称为上下文类,该类的对象维护多种状态。在本例中,Monster 类充当上下文,负责管理当前状态并委托请求给当前状态对象。
  • State(抽象状态类):定义了与环境类特定状态相关的行为接口。在这里,MonsterStatus 是抽象状态类,声明了状态相关的方法(如 Attacked),具体状态类需要实现这些方法。
  • ConcreteState(具体状态类):具体状态类是抽象状态类的子类,实现与环境类该状态相关的行为。每个状态类(如 MonsterStatus_FerocMonsterStatus_WorrMonsterStatus_FearMonsterStatus_Dead)实现了不同的 Attacked 方法,表现出不同的行为。

4. 状态模式的优点

  • 清晰的代码结构:通过将状态行为封装在状态对象中,避免了大量的条件语句,使代码更加清晰易读。
  • 易于扩展:增加新状态只需添加新的状态类,而无需修改现有代码,符合开闭原则。
  • 灵活的状态切换:状态之间的切换逻辑集中管理,便于维护和修改。

5. 状态模式的缺点

  • 类数量增加:每种状态都需要一个具体的状态类,可能导致类的数量增加,从而增加系统的复杂性。
  • 管理复杂性:状态之间的关系和切换逻辑可能变得难以管理,尤其是在状态较多时,可能需要额外的设计来处理状态转移。

6. 状态模式的适用场景

  • 对象的行为依赖于其状态,并且可以在运行时改变状态。

  • 需要避免使用大量条件语句来管理对象的状态。

  • 状态的改变会影响到对象的多个方法。

  • 行为依赖于状态:对象的行为依赖于其状态,并且可以在运行时改变状态。

  • 避免条件语句:需要避免使用大量条件语句来管理对象的状态,特别是在状态和行为较多的情况下。

  • 状态影响多个方法:状态的改变会影响到对象的多个方法,适合使用状态模式来管理这些变化。

完整代码

1. Monster.h
#ifndef __MONSTER__
#define __MONSTER__	
class MonsterStatus; //类前向声明
//怪物类
class Monster
{
public:Monster(int life);~Monster();public:void Attacked(int power);  //怪物被攻击public:int GetLife() //获取怪物血量{return m_life;}void SetLife(int life) //设置怪物血量{m_life = life;}MonsterStatus* getCurrentState() //获取怪物当前状态{return m_pState;}void setCurrentState(MonsterStatus* pstate) //设置怪物当前状态{m_pState = pstate;}private:int            m_life;    //血量(生命值)MonsterStatus* m_pState;  //持有状态对象
};
#endif
2. Monster.cpp
#include <iostream>
#include "Monster.h"
#include "MonsterStatus.h"using namespace std;//构造函数,怪物的初始状态从“凶悍”开始
Monster::Monster(int life) :m_life(life), m_pState(nullptr)
{m_pState = MonsterStatus_Feroc::getInstance();
}//析构函数
Monster::~Monster(){}//怪物被攻击void Monster::Attacked(int power)
{m_pState->Attacked(power, this);
}
3. MonsterStatus.h
#ifndef __MONSTERSTATUS__
#define __MONSTERSTATUS__
class Monster; //类前向声明
//怪物状态类的父类
class MonsterStatus
{
public:virtual void Attacked(int power, Monster* mainobj) = 0;virtual ~MonsterStatus() {}
};
//凶悍状态类
class MonsterStatus_Feroc :public MonsterStatus
{
public:virtual void Attacked(int power, Monster* mainobj);public:static MonsterStatus_Feroc* getInstance(){static MonsterStatus_Feroc instance;return &instance;}};//不安状态类
class MonsterStatus_Worr :public MonsterStatus
{
public:virtual void Attacked(int power, Monster* mainobj);public:static MonsterStatus_Worr* getInstance(){static MonsterStatus_Worr instance;return &instance;}};//恐惧状态类
class MonsterStatus_Fear :public MonsterStatus
{
public:virtual void Attacked(int power, Monster* mainobj);public:static MonsterStatus_Fear* getInstance(){static MonsterStatus_Fear instance;return &instance;}};//死亡状态类
class MonsterStatus_Dead :public MonsterStatus
{
public:virtual void Attacked(int power, Monster* mainobj);public:static MonsterStatus_Dead* getInstance(){static MonsterStatus_Dead instance;return &instance;}};
#endif
4. MonsterStatus.cpp
#include <iostream>
#include "Monster.h"
#include "MonsterStatus.h"using namespace std;//各个状态子类的Attacked成员函数实现代码
void MonsterStatus_Feroc::Attacked(int power, Monster* mainobj)
{int orglife = mainobj->GetLife();  //暂存原来的怪物血量值用于后续比较		if ((orglife - power) > 400)       //怪物原来处于凶悍状态,现在依旧处于凶悍状态{//状态未变mainobj->SetLife(orglife - power); //怪物剩余的血量cout << "怪物处于凶悍状态中,对主角进行疯狂的反击!" << std::endl;//处理其他动作逻辑比如反击}else{//不管下个状态是啥,总之不会是凶悍状态,只可能是不安、恐惧、死亡状态之一,先无条件转到不安状态去(不安状态中会进行再次判断)mainobj->setCurrentState(MonsterStatus_Worr::getInstance());mainobj->getCurrentState()->Attacked(power, mainobj);}
}void MonsterStatus_Worr::Attacked(int power, Monster* mainobj)
{int orglife = mainobj->GetLife();if ((orglife - power) > 100)       //怪物原来处于不安状态,现在依旧处于不安状态{//状态未变mainobj->SetLife(orglife - power); //怪物剩余的血量cout << "怪物处于不安状态中,对主角进行反击并呼唤支援!" << std::endl;//处理其他动作逻辑比如反击和不停的呼唤支援}else{//不管下个状态是啥,总之不会是凶悍和不安状态,只可能是恐惧、死亡状态之一,先无条件转到恐惧状态去mainobj->setCurrentState(MonsterStatus_Fear::getInstance());mainobj->getCurrentState()->Attacked(power, mainobj);}
}void MonsterStatus_Fear::Attacked(int power, Monster* mainobj)
{int orglife = mainobj->GetLife();if ((orglife - power) > 0)       //怪物原来处于恐惧状态,现在依旧处于恐惧状态{//状态未变mainobj->SetLife(orglife - power); //怪物剩余的血量cout << "怪物处于恐惧状态中,处于逃跑之中!" << std::endl;//处理其他动作逻辑比如逃跑}else{//不管下个状态是啥,总之不会是凶悍、不安和恐惧状态,只可能是死亡状态mainobj->setCurrentState(MonsterStatus_Dead::getInstance());mainobj->getCurrentState()->Attacked(power, mainobj);}
}void MonsterStatus_Dead::Attacked(int power, Monster* mainobj)
{int orglife = mainobj->GetLife();if (orglife > 0){//还要把怪物生命值减掉mainobj->SetLife(orglife - power); //怪物剩余的血量//处理怪物死亡后事宜比如怪物尸体定时消失等}cout << "怪物死亡!" << std::endl;
}
5. main.cpp
#include <iostream>
#include "Monster.h"using namespace std;int main()
{Monster monster(500);cout << "怪物出生,当前处于凶悍状态,500点血!" << endl;monster.Attacked(20);monster.Attacked(100);monster.Attacked(200);monster.Attacked(170);monster.Attacked(100);monster.Attacked(100);return 0;
}

物剩余的血量
//处理怪物死亡后事宜比如怪物尸体定时消失等
}
cout << “怪物死亡!” << std::endl;
}


#### 5. main.cpp```cpp
#include <iostream>
#include "Monster.h"using namespace std;int main()
{Monster monster(500);cout << "怪物出生,当前处于凶悍状态,500点血!" << endl;monster.Attacked(20);monster.Attacked(100);monster.Attacked(200);monster.Attacked(170);monster.Attacked(100);monster.Attacked(100);return 0;
}

http://www.ppmy.cn/devtools/100406.html

相关文章

Golang 中的 Recover 处理错误

Golang 中的 recover 是一个鲜为人知但非常有趣和强大的功能。让我们看看它是如何工作的&#xff0c;以及在 Outreach.io 中如何利用它来处理 Kubernetes 中的错误。 Panic/Defer/Recover 基本上是 Golang 中对于其他编程语言中 throw/finally/catch 概念的替代品。它们有一些共…

NMS流程及示例代码

NMS在目标检测中的作用不再赘述&#xff0c;现在就该算法的方法和流程进行总结。 以某yolo模型输出的61440*6的数据为例&#xff0c;总共输出61440的bbox&#xff08;实际只有3个目标&#xff09;&#xff0c;每个bbox的格式为[cx,cy,w,h,conf,cls_score]&#xff0c;分别代表b…

python怎么去除换行符

在Python的编写过程中&#xff0c;获取到的字符串进场存在不明原因的换行和空格&#xff0c;如何整合成一个单句&#xff0c;成为问题。 方法&#xff1a; 一、去除空格 “ ”代表的为空格 "xyz".strip() # returns "xyz" "xyz".ls…

人社大赛算法赛题解题思路分享+第五名

关联比赛: [国家社保]全国社会保险大数据应用创新大赛 赛题背景分析及理解 本次比赛&#xff0c;“精准社保”的赛题为“基本医疗保险医疗服务智能监控”&#xff0c;由参赛队完成数据算法模型的开发设计&#xff0c;实现对各类医疗保险基金欺诈违规行为的准确识别。 在进行了…

【C#】【EXCEL】Bumblebee/Classes/ExEnums.cs

文章目录 Bumblebee/Classes/ExEnums.csFlow diagramDescriptionCode Bumblebee/Classes/ExEnums.cs Flow diagram #mermaid-svg-FB98N7ZCCccQ4Z38 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-FB98N7ZCCccQ4Z38…

建筑楼宇电气安全与能效管理

随着建筑业的发展&#xff0c;配电系统在楼宇建筑特别是高层建筑中的比重也随之加大。现代的建筑的功能越来越完善&#xff0c;变配电工程、空调工程、机电工程、电梯工程、消防工程等工程设施设备与建筑体相结合&#xff0c;敷设的电气线路变得更为复杂&#xff0c;火灾隐患明…

leetcode 数组+哈希+双指针+子串+滑动窗口

——————双指针 283. 移动零 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] …

如何利用命令模式实现一个手游后端架构

命令模式&#xff08;Command Pattern&#xff09;是一种行为设计模式&#xff0c;它允许将请求封装为对象&#xff0c;从而使用不同的请求、队列、日志来参数化其他对象。命令模式也支持可撤销的操作。虽然命令模式在图形用户界面&#xff08;GUI&#xff09;编程中最为常见&a…