状态模式——C++实现

news2025/1/24 14:05:16

目录

1. 状态模式简介

2. 代码示例

3. 单例状态对象

4. 状态模式与策略模式的辨析


1. 状态模式简介

状态模式是一种行为型模式

状态模式的定义:状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

通俗的说就是一个对象在不同的状态下拥有不同的行为。对象可以拥有多个不同的状态,不同状态下调用同一个接口会产生不同的行为。状态模式通过把状态封装成类,可以很好地维护一个对象的不同状态,并且方便地扩展新的状态。


举个例子:

假如在游戏程序中,要模拟一个怪物。怪物的总血量为100,当血量大于50时,怪物处于亢奋状态,怪物受击时会进行反击;当血量小于等于50时,怪物处于恐慌状态,受击时会选择逃跑。

在这个例子中,怪物具有明确的状态,并且在不同的状态下,同一个接口会有不同的行为。这种情况下就非常适合使用状态模式。

2. 代码示例

下面的代码实现了上文提到的怪物模拟程序:

#if 1

#include <iostream>

using namespace std;

class Monster;
class State
{
protected:
	Monster* monster_;
public:
	virtual ~State() {}
	State(Monster* m) :monster_(m) {}
	virtual void attacked(int damage) = 0;
};



class Monster
{
public:
	Monster();
	~Monster();
	void setState(State* state)
	{
		curState = state;
	}
	State* getExcitedState()
	{
		return excitedState;
	}
	State* getHorrifiedState()
	{
		return horrifiedState;
	}
	State* getDeadState()
	{
		return deadState;
	}
	void attacked(int damage)
	{
		curState->attacked(damage);
	}
	int getCurHealth()const { return health; }
	int reduceHealth(int damage)
	{
		health -= damage;health = max(0, health);
		return health;
	}
private:
	State* curState;
	State* excitedState;
	State* horrifiedState;
	State* deadState;
	int health = 100;
};

class ExcitedState : public State
{
public:
	using State::State;
	void attacked(int damage)
	{
		cout << "怪物的当前状态为 ExcitedState" << endl;
		cout << "怪物尝试反击" << endl;
		cout << "怪物受到" << damage << "点伤害" << endl;
		int curHealth = monster_->reduceHealth(damage);
		cout << "怪物剩余血量:" << curHealth << endl;
		if (curHealth <= 50)
		{
			monster_->setState(monster_->getHorrifiedState());
			cout << "怪物进入 HorrifiedState" << endl;
		}
	}
};

class HorrifiedState : public State
{
public:
	using State::State;
	void attacked(int damage)
	{
		cout << "怪物的当前状态为 HorrifiedState" << endl;
		cout << "怪物尝试逃跑" << endl;
		cout << "怪物受到" << damage << "点伤害" << endl;
		int curHealth = monster_->reduceHealth(damage);
		cout << "怪物剩余血量:" << curHealth << endl;
		if (curHealth <= 0)
		{
			monster_->setState(monster_->getDeadState());
			cout << "怪物进入 DeadState" << endl;
		}
	}
};

class DeadState : public State
{
public:
	using State::State;
	void attacked(int damage)
	{
		cout << "怪物的当前状态为 DeadState" << endl;
		cout << "怪物已经死亡, 无法受到伤害" << endl;
	}
};

Monster::Monster()
{
	excitedState = new ExcitedState(this);
	horrifiedState = new HorrifiedState(this);
	deadState = new DeadState(this);
	curState = excitedState;
}

Monster::~Monster()
{
	delete excitedState;
	delete horrifiedState;
	delete deadState;	
}


int main()
{
	Monster monster;
	monster.attacked(0);
	cout << "---------------------" << endl;
	monster.attacked(30);
	cout << "---------------------" << endl;
	monster.attacked(40);
	cout << "---------------------" << endl;
	monster.attacked(80);
	cout << "---------------------" << endl;
	monster.attacked(100);
	cout << "---------------------" << endl;
	return 0;
}

#endif 

运行结果如下图所示:

 

代码中增加了死亡状态,当怪物血量小于0时进入了死亡状态。

采用状态模式可以很方便地扩展,增加新的状态会非常便捷。

3. 单例状态对象

当状态对象不含有自身内部的状态时,可以考虑将状态类实现成单例模式

4. 状态模式与策略模式的辨析

状态模式策略模式的结构十分类似,两种模式的差别在于它们的目的不同。

  • 对于状态模式来说,可以将对象的一组行为封装在一个状态对象中,context对象(拥有状态的对象)的行为可以随时通过切换不同的状态对象而改变。随着时间的流逝,当前的状态也在多个状态对象中发生改变,以反映context内部的状态,context的行为也会改变。但是对于客户端代码对于context的状态对象可以毫无察觉,不需要了解。context的状态切换是在其内部进行的,客户端代码感知不到客户端只能感受到context的行为产生了变化,而无需了解其当前的状态是怎么样的
  • 对于策略模式来说,通常需要客户端主动指定context当前所需要的策略对象是哪一个。策略模式允许在程序运行过程中改变策略,但是对于某个context对象来说,通常只有一个当前最适合的策略。策略的切换是通过客户端代码主动发起的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2281452.html

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

相关文章

数据库SQLite和SCADA DIAView应用教程

课程简介 此系列课程大纲主要包含七个课时。主要使用到的开发工具有&#xff1a;SQLite studio 和 SCADA DIAView。详细的可成内容大概如下&#xff1a; 1、SQLite 可视化管理工具SQLite Studio &#xff1a;打开数据库和查询数据&#xff1b;查看视频 2、创建6个变量&#x…

java开发,IDEA转战VSCODE配置(mac)

一、基本java开发环境配置 前提&#xff1a;已经安装了jdk、maven、vscode&#xff0c;且配置了环境变量 1、安装java相关的插件 2、安装spring相关的插件 3、vscode配置maven环境 打开 VsCode -> 首选项 -> 设置&#xff0c;也可以在setting.json文件中直接编辑&…

python爬虫的学习流程(1-前提准备)

这里主要记录一下我的python爬虫初级的学习的流程 1.python爬虫入门实战课 什么是爬虫&#xff1f;众说纷纭&#xff0c;我们引用维基百科上对网络爬虫的介绍&#xff1a; 网络爬虫&#xff08;英语&#xff1a;Web crawler&#xff09;&#xff0c;也叫网络蜘蛛&#xff08;…

数据结构初阶之双向链表的介绍与双向链表的实现

一、概念与结构 带头双向循环链表 next &#xff1a;指向下一个结点&#xff08;后继结点&#xff09; prev &#xff1a;指向前一个结点&#xff08;前驱结点&#xff09; 二、实现双向链表 项目创建的时候&#xff0c;要创建一个头文件&#xff08;.h&#xff09;List.h …

CICD集合(六):Jenkins配置Editable Email Notification

CICD集合(六):Jenkins配置Editable Email Notification 1、系统配置 1.1、Jenkins Location 1.2、邮件通知 1、SMTP服务器:imap.exmail.qq.com (因qq企业邮箱) 2、邮箱后缀:@xxx.com 3、勾选:使用SMTP认证 用户名:

Golang 中除了加锁还有哪些安全读写共享变量的方式?

Golang 中除了加锁还有哪些安全读写共享变量的方式&#xff1f; 在 Golang 中&#xff0c;除了使用 Mutex 锁来保护共享变量外&#xff0c;还可以通过 Channel 和 原子性操作 来实现安全读写共享变量。 1. 使用 Channel 原理 Channel 是 Golang 中用于 Goroutine 之间通信的…

应用层协议 HTTP 讲解实战:从0实现HTTP 服务器

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 一&#xff1a;&#x1f525; HTTP 协议 &#x1f98b; 认识 URL&#x1f98b; urlencode 和 urldecode 二&#xff1a;&#x1f525; HTTP 协议请求与响应格式 &#x1f98b; HTTP 请求…

F/V/F/I频率脉冲信号转换器

F/V/F/I频率脉冲信号转换器 概述&#xff1a;捷晟达科技的JSD TFA-1001系列是一进一出频率脉冲信号转换器(F/V转换器),该频率转换器是将频率脉冲信号(方波、正弦波、锯齿波)转换成国际标准的模拟量电压(电流)信号,并远距离无失真传送到控制室(如:PLC,DCS,AD,PC采集系统)产品的输…

Windows的docker中安装gitlab

一.Windows的docker中安装gitlab 1.通过阿里云拉取镜像 docker pull registry.cn-hangzhou.aliyuncs.com/lab99/gitlab-ce-zh 2.在本地创建备份数据的目录 mkdir -p D:home/software/gitlab/etc mkdir -p D:home/software/gitlab/logs mkdir -p D:home/software/gitlab/dat…

【Linux】理解Linux中一切皆文件、缓冲区、ext2文件系统、软硬链接

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 1、如何理解在Linux中一切皆文件&#xff1f;1.1 概述1.2 文件类型1.3 优势 2、缓冲区2.1 为什么要引入缓冲区&#xff1f;2.2 缓…

在Docker 容器中安装 Oracle 19c

在 Docker 容器中安装 Oracle 19c 是可行的&#xff0c;但它相较于其他数据库&#xff08;如 MySQL、PostgreSQL 等&#xff09;会复杂一些&#xff0c;因为 Oracle 数据库有一些特定的要求&#xff0c;如操作系统和库的依赖&#xff0c;以及许可证问题。 不过&#xff0c;Ora…

【数据库】详解MySQL数据库中的事务与锁

目录 1.数据库事务 1.1.事务的四大特性 1.2.事务开启的方式 1.3.读一致性问题及其解决 2.MVCC解决读一致性问题原理 2.1.MVCC概念 2.2.准备环境 3.MySQL中的锁 3.1.行锁之共享锁 3.2.行锁之排它锁 1.数据库事务 数据库事务&#xff08;Transaction&#xff09;是一种…

springboot 配置redis

环境配置 springboot3.4 redis5.0.14 redis准备参考下面文章 window下安装redis以及启动 redis客户端安装 引入依赖 <!-- 集成redis依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-…

EEG代码实践:diffusion EEG——扩散模型生成EEG信号

2024/1/22&#xff1a; 原始EEG信号的生成说实话一直做不到让人满意的水平&#xff0c;之前做的MIEEG复现也迟迟没有调整到自己想要的程度&#xff0c;与论文中的效果还是有些差距。改换思路使用离散小波变换&#xff0c;用变换之后的信号做生成任务则好了许多。从大二开始一直…

Banana Pi BPI-RV2 开发板矽昌通信 RISC-V路由芯片SF21H8898优势亮点

Banana Pi BPI-RV3开源路由器 1. 8898芯片具备强大的网络加速硬件性能&#xff0c;能够在小字节报文条件下实现高效数据转发&#xff1a;  单WAN口性能&#xff1a;支持 64 字节报文单向转发速率达到 2.5 Gbps&#xff0c;双向转发速率为 5 Gbps。双WAN口性能&#xff1a;支…

光谱相机在智能冰箱的应用原理与优势

食品新鲜度检测 详细可点击查看汇能感知团队实验报告&#xff1a;高光谱成像技术检测食物新鲜度 检测原理&#xff1a;不同新鲜程度的食品&#xff0c;其化学成分和结构会有所不同&#xff0c;在光谱下的反射、吸收等特性也存在差异。例如新鲜肉类和蔬菜中的水分、蛋白质、叶…

xxljob执行失败,xxl-job remoting error(sl.nts.com), for url : http://xxxxxxxxxx/run

问题 项目部署后&#xff0c;发现xxljob没有正常工作&#xff0c;报错 尝试解决&#xff1a; &#xff08;1&#xff09;检查xxljob配置&#xff08;无问题&#xff09; &#xff08;2&#xff09;检查服务器hosts文件域名配置&#xff08;依旧无问题&#xff09; 各种能检查…

什么是全息展示

全息展示。这一术语来源于“全息图”&#xff08;Holography&#xff09;的概念&#xff0c;而“全息图”这个词是由希腊词根 "holos" 演变而来&#xff0c;意为“整体的”或“完整的”。全息技术的核心在于它能够捕捉并再现物体的所有光学信息——不仅仅是强度&…

服务器内部是如何运行的

服务器内部的运行可以从硬件和软件两个方面来解释。 一、硬件层面 服务器的硬件与普通计算机相似,但它通常具有更高的性能和更强的扩展性。服务器硬件包括: 1.中央处理单元(CPU):负责执行服务器上的计算任务。服务器一般配备多核心的高性能CPU,以支持多个请求并行处理…

【Linux】文件操作、系统IO相关操作、inode和输入输出重定向

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 1、理解文件1.1 狭义理解1.2 广义理解1.3 文件操作1.4 系统角度 2、系统文件IO2.1 文件相关操作2.2 文件描述符2.3 重定向 3、动静…