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 結構圖