2018-09-22 16:16:13ios
要避免過長的方法,面向對象設計其實是但願作到代碼的責任分解。ide
狀態(State)模式,當一個對象的內在狀態改變時容許改變其行爲,這個對象看起來就像是改變了其類。狀態模式主要解決的是當控制一個對象狀態轉換條件表示式過於複雜時的狀況。把狀態的判斷邏輯轉移到表示不一樣狀態的一系列類當中,能夠把複雜的判斷邏輯簡化。固然若果這個判斷條件很簡單,那麼就沒有必要用狀態模式了。函數
State:抽象狀態類,定義一個接口以封裝與Context的一個特定狀態相關的行爲。this
ConcreteState:具體狀態,每個子類實現一個與Context的一個狀態相關的行爲。要注意具體狀態和狀態之間還有可能會有狀態的變遷。spa
Context:維護一個ConcreteState子類的實例,這個實例定義當前的狀態。設計
優勢:code
1.將與特定狀態相關的行爲局部化,而且將不一樣的狀態分隔開來,將特定的狀態相關的行爲都放入一個對象中,因爲全部與狀態相關的代碼都存在於某個ConcreteState中,因此經過定義新的子類就能夠很容易的增長新的狀態和轉換。這樣作能消除龐大的條件分支語句,大的分支判斷會使得它們難以修改和擴展,裝填模式經過把各類狀態轉移邏輯分別到State的子類之間,來減小相互之間的依賴。對象
2.在狀態模式中,對象的行爲是其狀態中函數的結果,並在運行時根據狀態改變行爲,這就消除了對ifelse/switchcase的依賴。blog
缺點:接口
1.使用狀態模式必然會增長工程中類的數量。
2.因爲狀態模式的實現與結構較爲負責,若是使用不當很容易出錯。
3.當增長新的狀態時,則須要修改負責轉換的源代碼,不然不能轉換到新增的狀態。
適用場景:
1.當一個對象的行爲取決於它的狀態(也就是說存在大量if/else 或者switch/case的時候),而且它必須在運行時刻根據狀態改變它的行爲時,就能夠考慮使用狀態模式。
2.若是業務需求某項業務有多個狀態,一般都是一些枚舉常量,狀態的變化都是依靠大量的分支判斷語句來實現,此時應該考慮將每一種業務狀態定義爲一個State的子類,這樣這些對象就能夠不依賴於其它對象而獨立變化了。
場景:立刻期末考試了,據說不及格會……小於60,不及格:把填空寫錯的都給我回去抄三遍!大於等於60小於70,:不行呀,仍是須要加油,課文抄兩遍吧。大於等於70小於85,還不錯,抄一遍就能夠了。85以上,哎喲,此次考試這麼難,不錯呀,去玩吧。
1.抽象狀態類(State):這個類它要作什麼呢,其實,就是根據外部狀態的不一樣來作出不一樣的行爲,利用了多態的特性,State中有一個Handle接口用於根據狀態的不一樣來作出不一樣的反應(改變狀態)
#ifndef STATE_H_ #define STATE_H_ class Context; class State { public: virtual void handle(Context objGetCondition) = 0; State() = default; virtual ~State() = default; }; #endif
2.具體狀態類(這個類值得好好看一下。用很差就真的是災難)
#ifndef LESSTHAN60STATE_H_ #define LESSTHAN60STATE_H_ #include "State.h" #include "Between60And70State.h" #include <iostream> class LessThan60State : public State { public: void handle(Context objGetState) override; LessThan60State() = default; ~LessThan60State() { if(nullptr != m_Between60And70State) { delete m_Between60And70State; m_Between60And70State = nullptr; } } private: Between60And70State *m_Between60And70State{nullptr}; }; #endif #include "LessThan60State.h" #include "Context.h" void LessThan60State::handle(Context objGetState) { if(objGetState.getCondition() < 60 ) { std::cout << "Your socre is lower than 60.You need copy this text 3 times." << std::endl; } else { //exceed 60 ,turn up to state 70,不能中文註釋真的很痛苦 //Between60And70State objNewState; m_Between60And70State = new Between60And70State; objGetState.setState(m_Between60And70State); objGetState.request(); } } #ifndef BETWEEN60AND70STATE_H_ #define BETWEEN60AND70STATE_H_ #include "State.h" #include <iostream> class Between60And70State : public State { public: void handle(Context objGetState) override; Between60And70State() = default; ~Between60And70State() = default; }; #endif #include "Between60And70State.h" #include "Context.h" #include "Between70And85State.h" void Between60And70State::handle(Context objGetState) { int iSocre = objGetState.getCondition(); if(iSocre >= 60 && iSocre < 70) { std::cout << "your socre is "<< iSocre <<".You need to copy this 2 times." << std::endl; } else { //exceed 70 or lower than 60.Suppose that condition is all right( exceed than 70 ) //大於70分的時候要進行一次狀態的躍遷 Between70And85State objNewState; objGetState.setState(&objNewState); objGetState.request(); } } #ifndef BETWEEN70AND85STATE_H_ #define BETWEEN70AND85STATE_H_ #include "State.h" #include "Between85And100State.h" #include <iostream> class Between70And85State : public State { public: void handle(Context objGetState) override; Between70And85State() = default; ~Between70And85State() = default; private: Between85And100State *m_Between85And100State{nullptr}; }; #endif #include "Between70And85State.h" #include "Context.h" void Between70And85State::handle(Context objGetState) { int iSocre = objGetState.getCondition(); if(iSocre >=70 && iSocre < 85) { std::cout << "Good job.But you need copy this text 1 time." << std::endl; } else { //大於85分,躍遷到下一個狀態 //Between85And100State objNewState; m_Between85And100State = new Between85And100State; objGetState.setState(m_Between85And100State); objGetState.request(); } } #ifndef BETWEEN85AND100STATE_H_ #define BETWEEN85AND100STATE_H_ #include "State.h" #include "LessThan60State.h" #include <iostream> class Between85And100State : public State { public: void handle(Context objGetState) override; Between85And100State() = default; ~Between85And100State() { if(nullptr != m_LessThan60State ) { delete m_LessThan60State; m_LessThan60State = nullptr; } } private: LessThan60State* m_LessThan60State{nullptr}; }; #endif #include "Between85And100State.h" #include "Context.h" void Between85And100State::handle(Context objGetCondition) { int iSocre = objGetCondition.getCondition(); if(iSocre > 85 && iSocre <= 100 ) { std::cout << "Very good!Just playing." << std::endl; } else { //若是不知足條件,那麼就從最第一級的條件開始,爲了保證程序不出錯誤,在Context的setCondition方法裏設置條件的時候必需要對條件作一個符合這個系統的檢查 //不然模式將會陷入死循環 m_LessThan60State = new LessThan60State; //LessThan60State newState; objGetCondition.setState(m_LessThan60State); objGetCondition.request(); } }
3.上下文類(Context)
ifndef CONTEXT_H_ #define CONTEXT_H_ #include "State.h" #include "Between85And100State.h" #include <iostream> class Context { public: bool setCondition(const int iCondition) { if(iCondition < 0 || iCondition >100) { std::cout << "The input is error.Socre must between 0 and 100." << std::endl; return false; } m_iCondition = iCondition; return true; } int getCondition() const { return m_iCondition; } void setState(State* objState) { m_currentState = objState; } void setIniState(State* objState) { m_currentState = objState; } void request() { if(nullptr == m_currentState) { std::cout << "nullptr,you must call set initState first. " << std::endl; return; } m_currentState->handle(*const_cast<Context *>(this)); } Context() { //初始狀態設置爲85-100這個區間段,你們都是好學生嘛 //m_initState = new Between85And100State; // m_currentState = m_initState; } ~Context() { /*if(nullptr != m_initState) { delete m_initState; m_initState = nullptr; }*/ } private: int m_iCondition{0}; State *m_currentState{nullptr}; State *m_initState{nullptr}; }; #endif
4.Client
#include "Context.h" #include "Between85And100State.h" using namespace std; int main(int argc,char *argv[]) { Context objContext; bool bRet = objContext.setCondition(75); Between85And100State obj100State; objContext.setIniState(&obj100State); if(false == bRet) return (0); objContext.request(); return(1); }