状态模式——C++实现

目录

[1. 状态模式简介](#1. 状态模式简介)

[2. 代码示例](#2. 代码示例)

[3. 单例状态对象](#3. 单例状态对象)

[4. 状态模式与策略模式的辨析](#4. 状态模式与策略模式的辨析)


1. 状态模式简介

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

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

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


举个例子:

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

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

2. 代码示例

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

cpp 复制代码
#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对象来说,通常只有一个当前最适合的策略。策略的切换是通过客户端代码主动发起的。
相关推荐
basketball61628 分钟前
python 的对象序列化
开发语言·python
fie88891 小时前
钢结构件制造车间生产调度实例:MATLAB实现(基于遗传算法)
开发语言·matlab·制造
沐知全栈开发1 小时前
PHP 安装指南
开发语言
CSDN_RTKLIB1 小时前
【字符编码】有无BOM的UTF-8
c++
Highcharts.js1 小时前
Highcharts Grid 表格/网格安装 |官方安装文档说明
开发语言·javascript·表格组件·highcharts·官方文档·安装说明·网格组件
Chary20161 小时前
opengl 学习资料路径
c++·opengl
im_AMBER2 小时前
Leetcode 102 反转链表
数据结构·c++·学习·算法·leetcode·链表
Coder_Boy_2 小时前
基于SpringAI的在线考试系统-企业级软件研发工程应用规范实现细节
大数据·开发语言·人工智能·spring boot
lly2024062 小时前
SQL SELECT 语句详解
开发语言
今儿敲了吗2 小时前
01|多项式输出
c++·笔记·算法