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

news2024/9/21 1:52:39

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

    • C++ 设计模式——状态模式
      • 1. 主要组成成分
      • 2. 逐步构建状态模式
        • 1. 状态接口定义
        • 2. 具体状态类实现
        • 3. 上下文类的实现
        • 4. 主函数
      • 3. 状态模式 UML 图
        • 状态模式 UML 图解析
      • 4. 状态模式的优点
      • 5. 状态模式的缺点
      • 6. 状态模式的适用场景
      • 完整代码
        • 1. Monster.h
        • 2. Monster.cpp
        • 3. MonsterStatus.h
        • 4. MonsterStatus.cpp
        • 5. main.cpp

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 图

状态模式 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.coloradmin.cn/o/2075350.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

视频生成新突破:内容-运动潜在扩散模型(CMD)

人工智能咨询培训老师叶梓 转载标明出处 当前的视频扩散模型虽然在生成质量上取得了巨大进步&#xff0c;但在处理高维视频数据时仍然面临内存和计算资源的高需求。这些模型通常直接处理高维视频数据&#xff0c;导致在生成视频时需要大量的计算资源和内存消耗。为了解决这一问…

【嵌入式】总结参考——Linux下的裸机驱动开发

板型:正点原子 I.MX6UL MINI 屏幕&#xff1a;7寸 1024*600 立意&#xff1a;既是这一段学习的总结&#xff0c;也可作为入门指南的参考&#xff0c;不过并不能作为教程来看&#xff0c;实际学习还是要找相应的视频或文章教程。 一、历程 应该和使用这块板子的大部分人一样&a…

基于ESP32驱动LAN8720以太网收发器

文章目录 一、LAN8720A简介二、引脚说明芯片管脚配置示例演示 一、LAN8720A简介 LAN8720A是低功耗的10/100M以太网PHY芯片&#xff0c;支持通过RMII接口和MAC层通信。它包含一个全双工10-BASE-T/100BASE-TX收发器&#xff0c;支持10Mbps和100Mbps操作。可以自动协商以自动确定最…

深度学习与OpenCV:解锁计算机视觉的无限可能

在科技日新月异的今天&#xff0c;计算机视觉作为人工智能领域的一颗璀璨明珠&#xff0c;正以前所未有的速度改变着我们的生活与工作方式。而《深度学习》与OpenCV&#xff0c;作为这一领域的两大重要工具&#xff0c;更是为计算机视觉的入门与深入探索铺设了坚实的基石。本文…

Python集成学习和随机森林算法使用详解

概要 集成学习是一种通过组合多个模型来提高预测性能的机器学习方法。它通过将多个弱学习器的结果结合起来,形成一个强学习器,从而提升模型的准确性和稳健性。随机森林(Random Forest)是集成学习中一种非常流行且有效的算法,特别适用于分类和回归任务。本文将详细介绍Pyt…

【图论】Tarjan算法(强连通分量)

一、Tarjan算法简介 Tarjan算法是一种由美国计算机科学家罗伯特塔杨&#xff08;Robert Tarjan&#xff09;提出的求解有向图强连通分量的线性时间的算法。 二、强连通分量的概念 在有向图 G G G 中&#xff0c;如果任意两个不同的顶点相互可达&#xff0c;则称该有向图是强…

平价电容笔排行榜:2024开学季五大高人气电容笔测评推荐 !

随着开学季的到来&#xff0c;无纸化学习再次成为热议话题&#xff0c;而电容笔作为支持这一趋势的重要配件&#xff0c;自然也备受瞩目。面对市场上琳琅满目的品牌选择&#xff0c;找到最适合自己需求的那一款就成了一个不小的挑战。不用担心&#xff0c;作为一名资深的数码产…

基于FPGA的SD NAND Flash数据读写实现

1、存储芯片分类 目前市面上的存储芯片&#xff0c;大致可以将其分为3大类&#xff1a; ① EEPROM EEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器&#xff0c;是一种掉电后数据不丢失的存储芯片。EEPROM 可以在电脑上或专用设备…

【初阶数据结构】复杂度

b站复杂度链接 另一个复杂度链接 复杂度笔记

利用大型语言模型协作提升甲状腺结节超声诊断的一致性和准确性| 文献速递-基于深度学习的癌症风险预测与疾病预后应用

Title 题目 Collaborative Enhancement of Consistency and Accuracy in US Diagnosis of Thyroid Nodules Using Large Language Models 利用大型语言模型协作提升甲状腺结节超声诊断的一致性和准确性 Background 背景 Large language models (LLMs) hold substantial …

git仓库删除某个历史提交

目录 问题情况1情况2 问题 如果我们在开发过程中&#xff0c;存在一些验证性的提交或者失误性的提交&#xff0c;那么这些提交我们不想要了&#xff0c;怎么办&#xff1f; 情况1 如果是想要删除某个commitid之后的所有提交 那么git reset 可以满足你 git reset --hard 你要…

2001-2023年上市公司数字化转型年报词频统计(吴非、赵宸宇、甄红线等300+个关键词)

2001-2023年上市公司数字化转型年报词频统计&#xff08;吴非、赵宸宇、甄红线&#xff09; 1、时间&#xff1a;2001-2023年 2、来源&#xff1a;上市公司年报 3、参考文献&#xff1a;企业数字化转型与资本市场表现——来自股票流动性的经验证据&#xff08;吴非&#xff…

电脑浏览器打不开部分网页

电脑浏览器打不开部分网页 时间: 2024-08-25 问题描述: 电脑突然打不开部分网页 例如腾讯文档 夸克网盘 但其他网页能够正常打开 原因 可能为域名解析问题 更改DNS即可解决 解决办法 控制面板–> 网络和Internet—>网络连接—> WLAN----> 属性 —> Interne…

spring security怎么生成JWT返回前端,以及怎么自定义JWT认证过滤器

怎么生成JWT返回前端 1.先写一个类,里面含有jwt的生成解析验证过期时间的方法 package com.lzy.util;import io.jsonwebtoken.*; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.…

7-6 分段函数2

计算分段函数&#xff0c;测试数据分别是-1、5、12。 输入格式: 输入一个数。 输出格式: 直接输出保留6位小数的结果&#xff0c;没有其它任何附加字符&#xff0c;没有宽度控制。 输入样例: 11输出样例: 0.999912输入样例: 7输出样例: 8.000000 #include <stdio.h…

单片机裸机程序——程序架构

目 录 程序架构等同于思想体系一、前后台顺序法二、时间片轮询法 程序架构等同于思想体系 建一栋楼房&#xff0c;地基要先设计好&#xff0c;而不是马上砌砖&#xff0c;地基和布局都合理&#xff0c;房子就住得舒服&#xff0c;也不会闹心。 写一段程序也一样&#xff0c;程…

c++,python实现网络爬虫

前言&#xff1a; 社交网络中用户生成的海量数据&#xff0c;社交网络数据的多样性和复杂性 如何高效地从海量的数据中获取和处理我们需要的信息资源&#xff1f; 该微博爬虫能够从社交网络平台中地提取文本、图片和用户之间的转发关系&#xff0c;并将这些数据结构化存储到…

Python的Windows GUI自动化之Pywinauto(四)

引言&#xff1a; 我们上章节中打开了一个应用程序后&#xff0c;并打印了所有的控件信息&#xff0c;这些对于工具无法定位到的控件有很好的协助作用&#xff08;当然这个可以作为主要的查找控件的用法&#xff0c;也可以辅助使用&#xff0c;我一般是把这个作为辅助使用&…

【C++】初识C++模板与STL

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C内存管理 本章将简单分享C模板与STL相关知识&#xff0c;与之相关更多知识将留到下次更详细地来分享给大家 &#x1f3…

MySQL与ES数据实时同步,双写一致

一、简介 在项目的开发与运维过程中&#xff0c;MySQL 是业务数据库的核心角色&#xff0c;以其强大的事务处理能力和数据完整性保障&#xff0c;支撑着系统的稳定运行。随着数据量的急剧增长和查询复杂度的不断提升&#xff0c;单一依赖 MySQL 进行高效的数据检索显得日益吃力…