狀態模式(State Pattern)
定義
在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態。這樣以後就可以將該對象恢復到原先的狀態
- State類,抽象狀態類,定義一個接口以封裝與Context的一個特定狀態相關的行爲。
- ConcreteState類,具體狀態,每一個子類實現一個與Context的一個狀態相關的行爲。
- Context類,維護一個ConcreteState子類的實例,這個實例定義當前的狀態。
常用場景
- 一個對象的行爲取決於它的狀態,並且它必須在運行時刻根據狀態改變它的行爲;
- 一個操作中含有龐大的多分支的條件語句,且這些分支依賴於該對象的狀態。這個狀態通常用一個或多個枚舉常量表示。通常,有多個操作包含這一相同的條件結構。State 模式將每一個條件分支放入一個獨立的類中。這使得你可以根據自身情況將對象的狀態作爲一個對象,這一對象可以不依賴於其他對象而獨立變化。
優缺點
優點:
- 將與特定狀態相關的行爲局部化,並且將不同狀態的行爲分割開來。
- 可以消除龐大的條件分支語句。狀態模式通過把各種狀態轉移邏輯分佈到State的子類之間,來減少相互間的依賴。
缺點:
子類越多會帶來類膨脹的問題
C++實現
舉例:工作流開發
在軟件開發過程中,一個任務(用戶故事)都要經過需求、開發、測試、驗收等階段,不同的階段需要不同的人做相應的事,每個階段相當於一個狀態,此時用狀態模式比較合適。
類圖:
代碼:
/*!
*@file State.h
*@brief 狀態模式
*/
#ifndef STATE_H
#define STATE_H
#include <iostream>
// 狀態類
class State
{
public:
State() {}
virtual ~State() {}
virtual void Process() = 0;
};
// 需求
class RequestState : public State
{
public:
RequestState() {}
~RequestState() {}
void Process()
{
std::cout << "需求整理中" << std::endl;
}
};
// 開發
class DevelopState : public State
{
public:
DevelopState() {}
~DevelopState() {}
void Process()
{
std::cout << "開發中" << std::endl;
}
};
// 測試
class TestState : public State
{
public:
TestState() {}
~TestState() {}
void Process()
{
std::cout << "測試中" << std::endl;
}
};
// 驗收
class AcceptState : public State
{
public:
AcceptState() {}
~AcceptState() {}
void Process()
{
std::cout << "驗收中" << std::endl;
}
};
// 任務
class UserStory
{
public:
UserStory(State* state): m_state(state)
{
}
~UserStory()
{
if (m_state)
{
delete m_state;
m_state = nullptr;
}
}
void SetState(State* state)
{
if (m_state)
delete m_state;
m_state = state;
}
State* GetState()
{
return m_state;
}
void Process()
{
m_state->Process();
}
private:
State* m_state; // 內部狀態
};
void StateTest()
{
UserStory* pUserStory = new UserStory(new RequestState);
pUserStory->Process();
pUserStory->SetState(new DevelopState);
pUserStory->Process();
pUserStory->SetState(new TestState);
pUserStory->Process();
pUserStory->SetState(new AcceptState);
pUserStory->Process();
delete pUserStory;
pUserStory = nullptr;
}
#endif // STATE_H