设计模式之状态模式

一、状态模式的概念

状态模式属于行为型设计模式,它通过改变对象的内部状态而改变对象的行为,这个对象表现得就好像修改了它的类一样。

状态模式主要解决:当控制一个对象状态转换的条件表达式过于复杂时,把状态的判断逻辑转移到表现不同状态的一系列类当中,从而使复杂的判断逻辑简单化。

二、状态模式使用场景

1、行为随状态改变而改变的场景。
2、条件和分支语句的替代者。

三、状态模式构建方法

1、用户对象(上下文环境)类(Context)
拥有一个状态类型的成员,以标识对象的当前状态,并提供给客户端调用的接口。

2、抽象状态类(State)
封装与用户对象的特定状态相关行为的接口和方法。

3、具体状态类(ConcreteState)
实现抽象状态类定义的接口和方法。

四、状态模式的示例

// StatePattern.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <string>

#define DELETE_PTR(p) {if(p!=nullptr){delete (p); (p)=nullptr;}}

using namespace std;

// 根据时间点不同模仿一个人吃早饭、午饭、晚饭的状态,其他时间状态都设置在工作
class EatMeal;
//class MorningTimeState;
//class NoonTimeState;
//class NightTimeState;

// 抽象状态类(State)
class TimeState
{
public:
	virtual void changeTimeState(int timeState) = 0;
	virtual void toEatMeal(EatMeal *pEatMeal) = 0;
};

// 用户对象(上下文环境)类(Context)-去吃饭
class EatMeal
{
public:
	EatMeal()
	{
		m_curTimeState = nullptr;
	}

	~EatMeal()
	{
		DELETE_PTR(m_curTimeState);
	}

	void changeTimeState(int timeState)
	{
		m_timeState = timeState;
	}

	int getCurTime()
	{
		return m_timeState;
	}

	void setTimeState(TimeState *pCurTimeState)
	{
		m_curTimeState = pCurTimeState;
	}

	TimeState *getTimeState()
	{
		return m_curTimeState;
	}

	void toEatMeal()
	{
		m_curTimeState->toEatMeal(this);
	}

private:
	int m_timeState;
	TimeState *m_curTimeState;
};

// 具体状态类(ConcreteState)-吃早饭
class MorningTimeState : public TimeState
{
public:
	void changeTimeState(int timeState)
	{
		m_timeState = timeState;
	}

	virtual void toEatMeal(EatMeal *pEatMeal);
private:
	int m_timeState;
};

// 具体状态类(ConcreteState)-吃午饭
class NoonTimeState : public TimeState
{
public:
	void changeTimeState(int timeState)
	{
		m_timeState = timeState;
	}

	 virtual void toEatMeal(EatMeal *pEatMeal);
	
private:
	int m_timeState;
};

// 具体状态类(ConcreteState)- 吃晚饭
class NightTimeState : public TimeState
{
public:
	void changeTimeState(int timeState)
	{
		m_timeState = timeState;
	}

	virtual void toEatMeal(EatMeal *pEatMeal);
private:
	int m_timeState;
};

/*因为MorningTimeState、NoonTimeState、NightTimeState三个类中互相调用了类中的方法,
即使前置声明这三个类也不行,类的声明和实现必须分离才行,不分离的话会提示“使用了未定义的类型错误”*/

void MorningTimeState::toEatMeal(EatMeal *pEatMeal)
{
	if (pEatMeal->getCurTime() >= 7 && pEatMeal->getCurTime() <= 8) // 早饭
	{
		cout << "ISMILELI------------>洗刷完了,我要去吃早饭啦!" << endl;
	}
	else if(pEatMeal->getCurTime() >= 12 && pEatMeal->getCurTime() <= 13) // 下一个吃饭节点午饭
	{
		MorningTimeState *pMorningTimeState = dynamic_cast<MorningTimeState*>(pEatMeal->getTimeState());
		DELETE_PTR(pMorningTimeState);
		TimeState *pNoonTimeState = dynamic_cast<TimeState*>(new NoonTimeState);
		pEatMeal->setTimeState(pNoonTimeState);
		pEatMeal->getTimeState()->toEatMeal(pEatMeal);
	}
	else // 其他时间都在工作
	{
		cout << "ISMILELI------------>我是工作狂,我不爱睡觉,除了吃饭就是工作!" << endl;
	}
}

void NoonTimeState::toEatMeal(EatMeal *pEatMeal)
{
	if (pEatMeal->getCurTime() >= 12 && pEatMeal->getCurTime() <= 13) // 午饭
	{
		cout << "ISMILELI------------>中午到了,我要去吃午饭啦!" << endl;
	}
	else if(pEatMeal->getCurTime() >= 18 && pEatMeal->getCurTime() <= 20)// 下一个吃饭节点晚饭
	{
		NoonTimeState *pNoonTimeState = dynamic_cast<NoonTimeState*>(pEatMeal->getTimeState());
		DELETE_PTR(pNoonTimeState);
		TimeState *pNightTimeState = dynamic_cast<TimeState*>(new NightTimeState);
		pEatMeal->setTimeState(pNightTimeState);
		pEatMeal->getTimeState()->toEatMeal(pEatMeal);
	}
	else // 其他时间都在工作
	{
		cout << "ISMILELI------------>我是工作狂,我不爱睡觉,除了吃饭就是工作!" << endl;
	}
}

void NightTimeState::toEatMeal(EatMeal *pEatMeal)
{
	if (pEatMeal->getCurTime() >= 18 && pEatMeal->getCurTime() <= 20) // 晚饭
	{
		cout << "ISMILELI------------>下班时间到了,我要去吃晚饭啦!" << endl;
	}
	else if(pEatMeal->getCurTime() >= 7 && pEatMeal->getCurTime() <= 8)// 下一个吃饭节点早饭
	{
		NightTimeState *pNightTimeState = dynamic_cast<NightTimeState*>(pEatMeal->getTimeState());
		DELETE_PTR(pNightTimeState);
		TimeState *pMorningTimeState = dynamic_cast<TimeState*>(new MorningTimeState);
		pEatMeal->setTimeState(pMorningTimeState);
		pEatMeal->getTimeState()->toEatMeal(pEatMeal);
	}
	else // 其他时间都在工作
	{
		cout << "ISMILELI------------>我是工作狂,我不爱睡觉,除了吃饭就是工作!" << endl;
	}
}

int main()
{
	cout << "----------------------状态模式----------------------" << endl;
	EatMeal *pEatMeal = new EatMeal;
	TimeState *pCurTimeState = dynamic_cast<TimeState*>(new MorningTimeState);
	pEatMeal->setTimeState(pCurTimeState);
	
	pEatMeal->changeTimeState(7);
	pEatMeal->toEatMeal();

	pEatMeal->changeTimeState(13);
	pEatMeal->toEatMeal();

	
	pEatMeal->changeTimeState(18);
	pEatMeal->toEatMeal();

	pEatMeal->changeTimeState(21);
	pEatMeal->toEatMeal();

	// 指针pCurTimeState内存释放在pEatMeal析构函数中
	DELETE_PTR(pEatMeal);

    std::cout << "Hello World!\n";
	getchar();
}

运行结果:
在这里插入图片描述

五、状态模式的优缺点

优点:
1、把复杂的对象状态判断简单化。
2、将所有与某个状态有关的行为放到一个类中,可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
3、允许状态转换逻辑与状态对象合成一体,从而简化逻辑判断。
4、多个环境对象可以共享一个状态对象,减少系统中对象的个数。

缺点:
1、每增加一种状态都会增加一个类。
2、状态模式的结构与实现都较为复杂。
3、耦合性强,增加新的状态类需要修改负责状态转换的源代码。

能力有限,如有错误,多多指教。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章