1、作用
允许一个对象在其内部状态改变时改变它的行为。
每个人、事物在不同的状态下会有不同的表现,而一个状态在不同的表现下会转换为另一个状态。
举个例子:
我们去买一杯奶茶,有热饮、冷饮、和常温三种可供选择,我们首先选择了常温的,在奶茶开始制作的时,擡头看了看天气,现在烈日炎炎,想想一杯冰凉的奶茶是不是能够按下躁动的心,因此立马决定告诉店员,我需要改成冷饮,而店员呢,也就需要改变奶茶的制作流程。
2、解决的问题
我们在搬砖中经常会遇到几种状态的选择,比如简单的鼠标的三种状态,遇到这种情况时,通常的方式是使用switch-case语句实现,这种实现方式简单粗暴,很香。但是,如果有十几种状态,甚至几十种呢,如果还是像往常一样写switch-case语句,维护一大组这样的语句是异常困难并且很容易出错的。就算强悍的我们维护了这样一大组的switch-case,后续如果有新增加的状态和行为,就需要对这段代码重新改造增加,扩展性和维护会变得很差。
状态模式的出现很好的解决了这种情况,我们有很多的状态,每一个状态实现一个行为,状态改变时,对应的行为也就会跟着改变,这样我们在整个代码中就维护了一个状态。
#include<iostream>
using namespace std;
class Context;
class State
{
public:
virtual ~State(){}
virtual void Handle(Context *pContext)=0;
};
class Context
{
public:
Context(State* pState):m_pState(pState){}
~Context()
{
delete m_pState;
m_pState = NULL;
}
void Request()
{
if(NULL != m_pState)
m_pState->Handle(this);
}
void ChangeState(State* pState)
{
if(NULL != m_pState)
{
delete m_pState;
m_pState = NULL;
}
m_pState = pState;
}
private:
State *m_pState;
};
class HotDrinks : public State
{
public:
void Handle(Context* pContext);
};
class ColdDrinks : public State
{
public:
void Handle(Context* pContext);
};
void HotDrinks::Handle(Context* pContext)
{
cout << "Make a hot drink ..." << endl;
if(NULL != pContext) //突然改变 需要 冷饮
{
pContext->ChangeState(new ColdDrinks());
}
}
void ColdDrinks::Handle(Context* pContext)
{
cout << "Make a cold drink ..." << endl;
if(NULL!=pContext)
{
pContext->ChangeState(new HotDrinks());
}
}
int main()
{
Context* pContext = new Context(new HotDrinks()); //首先委会一份热饮的状态
pContext->Request();
pContext->Request(); //改变状态 ,要冷饮
delete pContext;
pContext = NULL;
return 0;
}
通过上面的例子我们可以看出,对于一杯奶茶来说,中间可以改变自己的状态,当然现实生活中奶茶并不是可以随便改变的,基本上是一锤定音的且不可更改的,要不然谁买单呢?
3、思考
- 整个过程中state的数量可能会很多,是不是做一个管理所有state的类StateManager会比较好呢,这个类统一管理所有state的切换,外界需要切换状态时只需要向该类提交申请就好。
- 整个状态的切换过程中,我们不停的进行了状态的申请和释放,上面的例子状态只切换两次,就进行了3次的对象申请和释放,因此,state应该实现为一个singleton,避免申请时的内存和时间的消耗
4、UML 结构图