一、狀態模式的概念
狀態模式屬於行爲型設計模式,它通過改變對象的內部狀態而改變對象的行爲,這個對象表現得就好像修改了它的類一樣。
狀態模式主要解決:當控制一個對象狀態轉換的條件表達式過於複雜時,把狀態的判斷邏輯轉移到表現不同狀態的一系列類當中,從而使複雜的判斷邏輯簡單化。
二、狀態模式使用場景
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、耦合性強,增加新的狀態類需要修改負責狀態轉換的源代碼。
能力有限,如有錯誤,多多指教。。。