原文地址:http://www.jb51.net/article/80713.htm
創(chuàng)新互聯(lián)建站咨詢熱線:13518219792,為您提供成都網(wǎng)站建設(shè)網(wǎng)頁(yè)設(shè)計(jì)及定制高端網(wǎng)站建設(shè)服務(wù),創(chuàng)新互聯(lián)建站網(wǎng)頁(yè)制作領(lǐng)域10多年,包括履帶攪拌車等多個(gè)方面擁有多年的網(wǎng)站推廣經(jīng)驗(yàn),選擇創(chuàng)新互聯(lián)建站,為網(wǎng)站錦上添花。
這篇文章主要介紹了state狀態(tài)模式及在C++設(shè)計(jì)模式編程中的使用實(shí)例,在設(shè)計(jì)模式中策略用來處理算法變化,而狀態(tài)則是透明地處理狀態(tài)變化,需要的朋友可以參考下
每個(gè)人、事物在不同的狀態(tài)下會(huì)有不同表現(xiàn)(動(dòng)作),而一個(gè)狀態(tài)又會(huì)在不同的表現(xiàn)下轉(zhuǎn)移到下一個(gè)不同的狀態(tài)(State)。最簡(jiǎn)單的一個(gè)生活中的例子就是:地鐵入口處,如果你放入正確的地鐵票,門就會(huì)打開讓你通過。在出口處也是驗(yàn)票,如果正確你就可以 ok,否則就不讓你通過(如果你動(dòng)作野蠻,或許會(huì)有報(bào)警(Alarm),:))。
有限狀態(tài)自動(dòng)機(jī)(FSM)也是一個(gè)典型的狀態(tài)不同,對(duì)輸入有不同的響應(yīng)(狀態(tài)轉(zhuǎn)移)。
通常我們?cè)趯?shí)現(xiàn)這類系統(tǒng)會(huì)使用到很多的 Switch/Case 語句,Case 某種狀態(tài),發(fā)生什么動(dòng)作,Case 另外一種狀態(tài),則發(fā)生另外一種狀態(tài)。但是這種實(shí)現(xiàn)方式至少有以下兩個(gè)問題:
當(dāng)狀態(tài)數(shù)目不是很多的時(shí)候,Switch/Case 可能可以搞定。但是當(dāng)狀態(tài)數(shù)目很多的時(shí)候(實(shí)際系統(tǒng)中也正是如此),維護(hù)一大組的 Switch/Case 語句將是一件異常困難并且容易出錯(cuò)的事情。
狀態(tài)邏輯和動(dòng)作實(shí)現(xiàn)沒有分離。在很多的系統(tǒng)實(shí)現(xiàn)中,動(dòng)作的實(shí)現(xiàn)代碼直接寫在狀態(tài)的邏輯當(dāng)中。這帶來的后果就是系統(tǒng)的擴(kuò)展性和維護(hù)得不到保證。
狀態(tài)模式就是被用來解決上面列出的兩個(gè)問題的,在狀態(tài)模式中我們將狀態(tài)邏輯和動(dòng)作實(shí)現(xiàn)進(jìn)行分離。當(dāng)一個(gè)操作中要維護(hù)大量的 case 分支語句,并且這些分支依賴于對(duì)象的狀態(tài)。狀態(tài)模式將每一個(gè)分支都封裝到獨(dú)立的類中。
狀態(tài)模式典型的結(jié)構(gòu)圖為:
狀態(tài)模式的實(shí)現(xiàn)
代碼片斷 1:State.h
//state.h #ifndef _STATE_H_ #define _STATE_H_ class Context; //前置聲明 class State{ public: State(); virtual ~State(); virtual void OperationInterface(Context* ) = 0; virtual void OperationChangeState(Context*) = 0; protected: bool ChangeState(Context* con,State* st); private: //bool ChangeState(Context* con,State* st); }; class ConcreteStateA:public State{ public: ConcreteStateA(); virtual ~ConcreteStateA(); virtual void OperationInterface(Context* ); virtual void OperationChangeState(Context*); protected: private: }; class ConcreteStateB:public State{ public: ConcreteStateB(); virtual ~ConcreteStateB(); virtual void OperationInterface(Context* ); virtual void OperationChangeState(Context*); protected: private: }; #endif //~_STATE_H_
代碼片斷 2:State.cpp
//State.cpp #include "State.h" #include "Context.h" #include <iostream> using namespace std; State::State(){ } State::~State(){ } void State::OperationInterface(Context* con){ cout<<"State::.."<<endl; } bool State::ChangeState(Context* con,State* st){ con->ChangeState(st); return true; } void State::OperationChangeState(Context* con){ } /// ConcreteStateA::ConcreteStateA(){ } ConcreteStateA::~ConcreteStateA(){ } void ConcreteStateA::OperationInterface(Context* con){ cout<<"ConcreteStateA::OperationInterface ......"<<endl; } void ConcreteStateA::OperationChangeState(Context* con){ OperationInterface(con); this->ChangeState(con,new ConcreteStateB()); } /// ConcreteStateB::ConcreteStateB(){ } ConcreteStateB::~ConcreteStateB(){ } void ConcreteStateB::OperationInterface(Context* con){ cout<<"ConcreteStateB::OperationInterface......"<<endl; } void ConcreteStateB::OperationChangeState(Context* con){ OperationInterface(con); this->ChangeState(con,new ConcreteStateA()); }
代碼片斷 3:Context.h
//context.h #ifndef _CONTEXT_H_ #define _CONTEXT_H_ class State; /** * **/ class Context{ public: Context(); Context(State* state); ~Context(); void OprationInterface(); void OperationChangState(); protected: private: friend class State; //表明在 State 類中可以訪問 Context 類的 private 字段 bool ChangeState(State* state); private: State* _state; }; #endif //~_CONTEXT_H_
代碼片斷 4:Context.cpp
//context.cpp #include "Context.h" #include "State.h" Context::Context(){ } Context::Context(State* state){ this->_state = state; } Context::~Context(){ delete _state; } void Context::OprationInterface(){ _state->OperationInterface(this); } bool Context::ChangeState(State* state){ ///_state->ChangeState(this,state); this->_state = state; return true; } void Context::OperationChangState(){ _state->OperationChangeState(this); }
代碼片斷 5:main.cpp
//main.cpp #include "Context.h" #include "State.h" #include <iostream> using namespace std; int main(int argc,char* argv[]){ State* st = new ConcreteStateA(); Context* con = new Context(st); con->OperationChangState(); con->OperationChangState(); con->OperationChangState(); if (con != NULL) delete con; if (st != NULL) st = NULL; return 0; }
代碼說明:狀態(tài)模式在實(shí)現(xiàn)中,有兩個(gè)關(guān)鍵點(diǎn):
1.將狀態(tài)聲明為 Context 的友元類(friend class),其作用是讓狀態(tài)模式訪問 Context的 protected 接口 ChangeSate()。
狀態(tài)及其子類中的操作都將 Context*傳入作為參數(shù),其主要目的是狀態(tài)類可以通過這個(gè)指針調(diào)用 Context 中的方法(在本示例代碼中沒有體現(xiàn))。這也是狀態(tài)模式和 Strategy模式的最大區(qū)別所在。
2.運(yùn)行了示例代碼后可以獲得以下的結(jié)果:連續(xù) 3 次調(diào)用了 Context 的 OprationInterface()因?yàn)槊看握{(diào)用后狀態(tài)都會(huì)改變(A-B-A),因此該動(dòng)作隨著 Context 的狀態(tài)的轉(zhuǎn)變而獲得了不同的結(jié)果。
關(guān)于State模式的一些需要注意的地方
這個(gè)模式使得軟件可以在不同的state下面呈現(xiàn)出完全不同的特征
不同的theme使得相同的元素呈現(xiàn)出不同的特點(diǎn)
不同的state下面相同的操作產(chǎn)生不同的效果
不同的狀態(tài)對(duì)相同的信息產(chǎn)生不同的處理
這個(gè)模式使得操作的state邏輯更加的清楚,省去了無數(shù)的state判斷,而state的擴(kuò)展性和可維護(hù)性和執(zhí)行效率也大幅度的上升。關(guān)于state,有如下幾點(diǎn)要注意的地方:
1.所有的state應(yīng)該被一個(gè)類(State Manager Class)管理:
state之間的跳轉(zhuǎn)和轉(zhuǎn)換是非常復(fù)雜的,有時(shí)一些state可能要跳轉(zhuǎn)的目標(biāo)state有幾十個(gè),這個(gè)時(shí)候我們需要一個(gè)管理類(State Manager )來統(tǒng)一的管理這些state的切換,例如目標(biāo)state的初始化和申請(qǐng)?zhí)D(zhuǎn)state的結(jié)束處理,以及一些state間共享數(shù)據(jù)的存儲(chǔ)和處理。與其稱這個(gè)Manager 為管理類,不如說是一個(gè)中間類,它實(shí)現(xiàn)了state之間的解隅,使得各個(gè)state之間不比知道target state的具體信息,而只要向Manager申請(qǐng)?zhí)D(zhuǎn)就可以了。使得各個(gè)state的模塊化更好,更加的靈活
2.所有的state都應(yīng)該從一個(gè)state基類繼承:
既然state要教給一個(gè)manager來管理,那么自然的,這些state都應(yīng)該從一個(gè)父類繼承下來,這樣manager并不需要知道很多子類的信息,一個(gè)最單純的manager只要只要管理一個(gè)這樣的基類的指針就可以了。另外,我們還可以統(tǒng)一的把state的一些共有的屬性放在這里
3.state應(yīng)該實(shí)現(xiàn)為一個(gè)singleton:
state并不需要總是被申請(qǐng),這樣可能會(huì)造成管理上的混亂,state資源的申請(qǐng)也不應(yīng)該可以任意進(jìn)行,事實(shí)上,state的申請(qǐng)權(quán)限應(yīng)該只有 Manager才有,并且有且只有一次。在這樣的情況下,state的構(gòu)造函數(shù)似乎應(yīng)該被聲明為protected or private ,而Manager應(yīng)該被聲明為state的友元,但是友元被看成是破壞類的封裝性的一種做法,這一點(diǎn)上,我很矛盾,所以在這一條上我只能采取一種漠視的態(tài)度。
4.應(yīng)該做一個(gè)state么?這是一個(gè)問題:
state可以說是if-else的一種替代品,極端的情況下面state可以讓你的程序中if-else程序塊消失得無影無蹤,但是,這并不是銀彈。state對(duì)于狀態(tài)可預(yù)知的情況下非常有效,但是對(duì)于state不可預(yù)知,或者相似的state數(shù)量太多。過多的state會(huì)造成class的粒度過細(xì),程序反而不簡(jiǎn)潔。在這樣的情況下,你應(yīng)該考慮使用if-else程序塊來替代state。
例如:
有這樣的一個(gè)程序,它可以生成任意形狀的多邊形,而多邊形的各個(gè)節(jié)點(diǎn)是可以移動(dòng)的,問題就來了。
我并不知道用戶將要使用多少個(gè)節(jié)點(diǎn)的多邊形,因此我無法的創(chuàng)建那么多相應(yīng)的state來使得這樣一個(gè)程序正常工作。state大多數(shù)都是確定的,對(duì)于不確定的,state似乎無能為力,例如此例
一種解決方法是我利用Manager傳遞給state一個(gè)state參數(shù),讓state有機(jī)會(huì)知道用戶的操作意圖,在這個(gè)例子里面是讓state知道用戶打算操作某一個(gè)節(jié)點(diǎn),而state根據(jù)這個(gè)state參數(shù)來處理用戶的操作,比如說,state得到的是用戶操作的某一個(gè)點(diǎn)的index ,而state只要寫
points[index].moveTo(points[index].getX()+offset_x , points[index].getY()+offset_y);
就可以,從而避免了state過多出現(xiàn)的問題。
當(dāng)前題目:詳解state狀態(tài)模式及在C++設(shè)計(jì)模式編程中的使用實(shí)例
文章URL:http://chinadenli.net/article2/pigeoc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航、網(wǎng)站建設(shè)、ChatGPT、App開發(fā)、動(dòng)態(tài)網(wǎng)站、響應(yīng)式網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)