状态模式——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对象来说,通常只有一个当前最适合的策略。策略的切换是通过客户端代码主动发起的。
相关推荐
hweiyu009 分钟前
C#学习教程(附电子书资料)
开发语言·学习·c#
q5673152310 分钟前
图片爬虫通过模板及使用说明
开发语言·爬虫·tcp/ip·golang
superior tigre15 分钟前
C++学习:六个月从基础到就业——C++11/14:列表初始化
c++·学习
正在走向自律22 分钟前
Conda 完全指南:从环境管理到工具集成
开发语言·python·conda·numpy·fastapi·pip·开发工具
xiaolin033327 分钟前
【设计模式】- 行为型模式1
设计模式·状态模式·责任链模式·策略模式·命令模式·模板方法模式·行为型模式
啊吧怪不啊吧27 分钟前
C/C++之内存管理
开发语言·汇编·c++
北极象29 分钟前
Go语言处理HTTP下载中EOFFailed
开发语言·http·golang
superior tigre33 分钟前
C++学习:六个月从基础到就业——C++11/14:decltype关键字
c++·学习
技术流浪者36 分钟前
C/C++实践(十)C语言冒泡排序深度解析:发展历史、技术方法与应用场景
c语言·数据结构·c++·算法·排序算法
tyatyatya1 小时前
MATLAB 自然语言处理入门教程
开发语言·matlab·自然语言处理