日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

[设计模式][c++]状态切换模式

發(fā)布時間:2024/9/5 c/c++ 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [设计模式][c++]状态切换模式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉(zhuǎn)自:http://blog.csdn.net/yongh701/article/details/49154439

?

狀態(tài)模式也是設(shè)計模式的一種,這種設(shè)計模式思想不復(fù)雜,就是實現(xiàn)起來的代碼有點復(fù)雜。主要出現(xiàn)在類傳遞參數(shù)上,尤其是C++這種不能直接類間互相調(diào)用都語言,實現(xiàn)狀態(tài)模式更難,當(dāng)然,一切設(shè)計模式都是為了更簡短的主函數(shù)。

狀態(tài)模式是當(dāng)一個對象的內(nèi)在狀態(tài)改變時允許改變其行為,這個對象看起來像是改變了其類,主要解決的是當(dāng)控制一個對象狀態(tài)轉(zhuǎn)換的條件表達式過于復(fù)雜時的情況。把狀態(tài)的判斷邏輯轉(zhuǎn)移到表示不同的一系列類當(dāng)中,可以把復(fù)雜的邏輯判斷簡單化。主要有以下三種角色:

1、上下文環(huán)境(Context):它定義了客戶程序需要的接口并維護一個具體狀態(tài)角色的實例,將與狀態(tài)相關(guān)的操作委托給當(dāng)前的Concrete State對象來處理。
2、抽象狀態(tài)(State):定義一個接口以封裝使用上下文環(huán)境的的一個特定狀態(tài)相關(guān)的行為。
3、具體狀態(tài)(Concrete State):實現(xiàn)抽象狀態(tài)定義的接口。

說是這樣的意思:

舉個例子來說明吧,如下圖:

現(xiàn)在要求再主函數(shù)中,直接一行代碼context->switch_state();從狀態(tài)A切到狀態(tài)B。

這里利用狀態(tài)模式來實現(xiàn),具體狀態(tài)就是狀態(tài)A與狀態(tài)B,然后上下文存在一個“轉(zhuǎn)換狀態(tài)”的方法。之后狀態(tài)A與狀態(tài)B共同接口就是抽象狀態(tài)State。具體實現(xiàn)代碼如下:

?

[cpp]?view plaincopy print?
  • #include<iostream>??
  • using?namespace?std;??
  • class?Context;//類,上下文,的提前引用,主要是用于通過C++的編譯,需要提前聲明這個類??
  • class?State{//抽象狀態(tài)??
  • public:??
  • ????virtual?void?switch_state()=0;//其實就是一個接口,轉(zhuǎn)換狀態(tài)的方法switch_state()全部寫在這里??
  • };??
  • //具體狀態(tài)??
  • //每一個具體狀態(tài),都必須有私有變量上下文Context?*context;??
  • //每一個具體狀態(tài)的構(gòu)造方法,都必須用this->context=context;實現(xiàn)將自己注冊到上下文中。??
  • //不得在每一個具體狀態(tài)中實現(xiàn)轉(zhuǎn)換狀態(tài)的方法switch_state(),只能在類外實現(xiàn),因為C++禁止類的互相調(diào)用,否則會出現(xiàn)error?C2027:?使用了未定義類型的錯誤??
  • class?StateA:public?State{??
  • private:??
  • ????Context?*context;??
  • public:??
  • ????StateA(Context?*context){??
  • ????????this->context=context;??
  • ????}??
  • ????void?switch_state();??
  • };??
  • class?StateB:public?State{??
  • private:??
  • ????Context?*context;??
  • public:??
  • ????StateB(Context?*context){??
  • ????????this->context=context;??
  • ????}??
  • ????void?switch_state();??
  • };??
  • //上下文的實現(xiàn),里面包含一個設(shè)置抽象狀態(tài)的方法,各個取具體狀態(tài)的方法。??
  • /*?
  • ????同時,抽象狀態(tài)中定義的實現(xiàn)狀態(tài)方法,這里要有?
  • ????void?switch_state(){?
  • ????????state->switch_state();?
  • ????}?
  • ????的實現(xiàn),用于暴露給客戶端調(diào)用?
  • */??
  • class?Context{??
  • private:??
  • ????State?*stateA,*stateB,*state;??
  • public:??
  • ????Context(){??
  • ????????stateA=new?StateA(this);??
  • ????????stateB=new?StateB(this);??
  • ????????this->state=stateA;??
  • ????}??
  • ????void?switch_state(){??
  • ????????state->switch_state();??
  • ????}??
  • ????void?setState(State*?state){??
  • ????????this->state=state;??
  • ????}??
  • ????State*?getStateA(){??
  • ????????return?stateA;??
  • ????}??
  • ????State*?getStateB(){??
  • ????????return?stateB;??
  • ????}??
  • };??
  • //各個具體狀態(tài)中,所對應(yīng)轉(zhuǎn)換狀態(tài)方法。??
  • void?StateA::switch_state(){??
  • ????this->context->setState(this->context->getStateB());//轉(zhuǎn)換到B狀態(tài)的特定寫法??
  • ????cout<<"已轉(zhuǎn)換到狀態(tài)B"<<endl;??
  • };??
  • void?StateB::switch_state(){??
  • ????this->context->setState(this->context->getStateA());//轉(zhuǎn)換到A狀態(tài)的特定寫法??
  • ????cout<<"已轉(zhuǎn)換到狀態(tài)A"<<endl;??
  • };??
  • //主函數(shù)??
  • int?main(){??
  • ????Context?*context=new?Context();??
  • ????context->switch_state();??
  • ????context->switch_state();??
  • ????context->switch_state();??
  • ????context->switch_state();??
  • ????return?0;??
  • }??

  • 運行結(jié)果如下圖:

    ?

    可以看到,在主函數(shù)中,只是初始化了上下文,然而不停調(diào)用上下文的switch_state()方法,卻在兩個具體狀態(tài)A與B之間跳轉(zhuǎn)。然而,同樣的一句switch_state()有著不同實現(xiàn),打印的內(nèi)容是不同。

    上述代碼還有C++的特色,各個具體狀態(tài)中,所對應(yīng)轉(zhuǎn)換狀態(tài)方法,只能在類外實現(xiàn),而不能在直接在StateA與StateB里面實現(xiàn)。因為C++不像Java,Java編譯的時候一次性把所有東西讀進去。C++是見一行讀一行。這里Context類用到State,StateA與StateB用到了Context,類間相互調(diào)用在C++中是不行的。

    同時,注意在上下文類Context的構(gòu)造類,對各個具體狀態(tài)初始化,也就是注冊各個具體狀態(tài)到上下文,否則編譯是過了,卻在程序中出現(xiàn)空指針。

    那么這種狀態(tài)模式到底有什么呢?這里用一道2011年下半年的軟件設(shè)計師軟考題目再來說明:

    題目是這樣的:

    某大型商場內(nèi)安裝了多個簡易的紙巾售賣機,自動出售2元錢一包的紙巾,且每次僅售出一包紙巾,紙巾售賣機的狀態(tài)圖如圖5-1所示:

    ?

    采用狀態(tài)(State)模式來實現(xiàn)該紙巾售賣機,得到如圖5-2所示的類圖,其中類State為抽象類,定義了投幣、退幣、出紙巾等方法接口。類SoldOutState、NoQuarterState、HasQuarterState、SoldState分別對應(yīng)圖5-1紙巾售賣機的4種狀態(tài)。售出紙巾、紙巾售賣、買有投幣、有2元錢。

    這里很顯然,如果不用狀態(tài)模式,會產(chǎn)生大量的if...else語句,代碼將很不容易改變,,難以拓展。狀態(tài)轉(zhuǎn)換隱藏在條件語句中,所以并不明顯未來加入的代碼可能導(dǎo)致bug。

    那么用狀態(tài)模式,先來分析一下,這里具體狀態(tài)有4個,分別對應(yīng)4個類,TissueMachine類就是開放給主函數(shù)的上下文,而用戶能夠操作的地方,有3個,一個是投幣、一個是退幣,另一個是按“出紙巾”,這是上下文TissueMachine能給主函數(shù)調(diào)用的方法就這三個。而沒有提到的售出方法dispense,是上下文自身內(nèi)部的狀態(tài)裝換,因此只在售出紙巾這個狀態(tài)中實現(xiàn)這個方法。不過,由于抽象狀態(tài)State定義了這4個方法的接口,因此,4個具體狀態(tài)都要有這4個方法,當(dāng)然具體實現(xiàn)因狀態(tài)不同而不同,具體代碼如下:

    ?

    [cpp]?view plaincopy print?
  • #include<iostream>??
  • using?namespace?std;??
  • //以下為類的定義部分??
  • class?TissueMachine;//類的提前引用??
  • //抽象狀態(tài)??
  • class?State{??
  • public:??
  • ????virtual?void?insertQuarter()=0;//“投幣”按鈕被按下??
  • ????virtual?void?ejectQuarter()=0;//“退幣”按鈕被按下??
  • ????virtual?void?turnCrank()=0;//“出紙巾”按鈕被按下??
  • ????virtual?void?dispense()=0;//正在賣出紙巾??
  • };??
  • ??
  • //具體狀態(tài)??
  • class?SoldOutState:public?State{//紙巾售完狀態(tài)??
  • private:??
  • ????TissueMachine*?tissueMachine;??
  • public:??
  • ????SoldOutState(TissueMachine?*tissueMachine){??
  • ????????this->tissueMachine=tissueMachine;??
  • ????}??
  • ????void?insertQuarter();??
  • ????void?ejectQuarter();??
  • ????void?turnCrank();??
  • ????void?dispense();??
  • };??
  • class?NoQuarterState:public?State{//沒有投幣狀態(tài)??
  • private:??
  • ????TissueMachine*?tissueMachine;??
  • public:??
  • ????NoQuarterState(TissueMachine?*tissueMachine){??
  • ????????this->tissueMachine=tissueMachine;??
  • ????}??
  • ????void?insertQuarter();??
  • ????void?ejectQuarter();??
  • ????void?turnCrank();??
  • ????void?dispense();??
  • };??
  • class?HasQuarterState:public?State{//有2元錢(已投幣狀態(tài))??
  • private:??
  • ????TissueMachine*?tissueMachine;??
  • public:??
  • ????HasQuarterState(TissueMachine?*tissueMachine){??
  • ????????this->tissueMachine=tissueMachine;??
  • ????}??
  • ????void?insertQuarter();??
  • ????void?ejectQuarter();??
  • ????void?turnCrank();??
  • ????void?dispense();??
  • };??
  • class?SoldState:public?State{//出售紙巾狀態(tài)??
  • private:??
  • ????TissueMachine*?tissueMachine;??
  • public:??
  • ????SoldState(TissueMachine?*tissueMachine){??
  • ????????this->tissueMachine=tissueMachine;??
  • ????}??
  • ????void?insertQuarter();??
  • ????void?ejectQuarter();??
  • ????void?turnCrank();??
  • ????void?dispense();??
  • };??
  • ??
  • //上下文??
  • class?TissueMachine{??
  • private:??
  • ????State?*soldOutState,*noQuarterState,*hasQuarterState,*soldState,*state;??
  • ????int?count;//紙巾數(shù)??
  • public:??
  • ????TissueMachine(int?numbers){//構(gòu)造函數(shù),定義初始狀態(tài)有紙巾售賣機有多少紙巾??
  • ????????soldOutState=new?SoldOutState(this);??
  • ????????noQuarterState=new?NoQuarterState(this);??
  • ????????hasQuarterState=new?HasQuarterState(this);??
  • ????????soldState=new?SoldState(this);??
  • ????????this->count=numbers;??
  • ????????if?(count>?0)?{????
  • ????????????this->state=noQuarterState;//開始為沒有投幣的狀態(tài)??
  • ????????}??
  • ????};??
  • ????//開放給主函數(shù)調(diào)用的方法??
  • ????void?insertQuarter(){??
  • ????????state->insertQuarter();??
  • ????}??
  • ????void?ejectQuarter(){??
  • ????????state->ejectQuarter();??
  • ????}??
  • ????void?turnCrank(){??
  • ????????state->turnCrank();??
  • ????????state->dispense();??
  • ????}??
  • ????//數(shù)據(jù)傳遞的getter與setter??
  • ????void?setState(State*?state){??
  • ????????this->state=state;??
  • ????}??
  • ????State*?getHasQuarterState(){??
  • ????????return?hasQuarterState;??
  • ????}??
  • ????State*?getNoQuarterState(){??
  • ????????return?noQuarterState;??
  • ????}??
  • ????State*?getSoldState(){??
  • ????????return?soldState;??
  • ????}?????
  • ????State*?getSoldOutState(){??
  • ????????return?soldOutState;??
  • ????}??
  • ????int?getCount(){??
  • ????????return?count;??
  • ????};??
  • ????void?setCount(int?numbers){??
  • ????????this->count=numbers;??
  • ????};??
  • };??
  • ??
  • //具體狀態(tài)中各個方法的具體實現(xiàn)。??
  • //紙巾售完狀態(tài)??
  • void?SoldOutState::insertQuarter(){???????
  • ????cout<<"機器無紙巾,已退回硬幣!"<<endl;??
  • }??
  • void?SoldOutState::ejectQuarter(){??
  • ????cout<<"自動售貨機根本沒有硬幣!"<<endl;??
  • }??
  • void?SoldOutState::turnCrank(){??
  • ????cout<<"機器無紙巾,請不要操作機器"<<endl;??
  • }??
  • void?SoldOutState::dispense(){??
  • }??
  • //沒有投幣狀態(tài)??
  • void?NoQuarterState::insertQuarter(){?????????
  • ????tissueMachine->setState(tissueMachine->getHasQuarterState());??
  • ????cout<<"已投幣!"<<endl;??
  • }??
  • void?NoQuarterState::ejectQuarter(){??
  • ????cout<<"自動售貨機根本沒有硬幣!"<<endl;??
  • }??
  • void?NoQuarterState::turnCrank(){??
  • ????cout<<"請投幣"<<endl;??
  • }??
  • void?NoQuarterState::dispense(){??
  • }??
  • //有2元錢(已投幣狀態(tài))??
  • void?HasQuarterState::insertQuarter(){??
  • ????cout<<"已投幣!請不要重復(fù)投幣!已退回重復(fù)投幣!"<<endl;??
  • }??
  • void?HasQuarterState::ejectQuarter(){??
  • ????tissueMachine->setState(tissueMachine->getNoQuarterState());??
  • ????cout<<"已取幣!"<<endl;??
  • }??
  • void?HasQuarterState::turnCrank(){??
  • ????tissueMachine->setState(tissueMachine->getSoldState());??
  • ????cout<<"請等待自動售貨機出紙巾!"<<endl;??
  • }??
  • void?HasQuarterState::dispense(){??
  • }??
  • //出售紙巾狀態(tài)??
  • void?SoldState::insertQuarter(){??
  • ????cout<<"請等待自動售貨機出紙巾!請不要投幣!已退回投幣!"<<endl;??
  • }??
  • void?SoldState::ejectQuarter(){??
  • ????tissueMachine->setState(tissueMachine->getNoQuarterState());??
  • ????cout<<"請等待自動售貨機出紙巾!無法取回已消費的硬幣!"<<endl;??
  • }??
  • void?SoldState::turnCrank(){??
  • ????cout<<"請等待自動售貨機出紙巾!已響應(yīng)你的操作!"<<endl;??
  • }??
  • void?SoldState::dispense(){//售出紙巾動作??
  • ????if(tissueMachine->getCount()>0){??
  • ????????tissueMachine->setState(tissueMachine->getNoQuarterState());??
  • ????????tissueMachine->setCount(tissueMachine->getCount()-1);??
  • ????????cout<<"你的紙巾,請拿好!"<<endl;??
  • ????}??
  • ????else{??
  • ????????tissueMachine->setState(tissueMachine->getSoldOutState());??
  • ????????cout<<"已退回你的硬幣!紙巾已賣光,等待進貨!"<<endl;??
  • ????}??
  • }?????
  • //主函數(shù)??
  • int?main(){??
  • ????TissueMachine?*tissueMachine=new?TissueMachine(1);??
  • ????cout<<"紙巾數(shù):"<<tissueMachine->getCount()<<endl;??
  • ????tissueMachine->insertQuarter();//投幣??
  • ????tissueMachine->turnCrank();//取紙巾??
  • ????cout<<"紙巾數(shù):"<<tissueMachine->getCount()<<endl;//不投幣取紙巾測試??
  • ????tissueMachine->turnCrank();???
  • ????cout<<"紙巾數(shù):"<<tissueMachine->getCount()<<endl;//售完紙巾,投幣取紙巾測試??
  • ????tissueMachine->insertQuarter();????
  • ????tissueMachine->turnCrank();???
  • ????return?0;??
  • }??

  • 運行結(jié)果如下:

    ?

    這里設(shè)置紙巾機一開始僅有1個紙巾,分別做不同的測試,可見紙巾自動售貨機有不同的響應(yīng)。

    轉(zhuǎn)載于:https://www.cnblogs.com/lyggqm/p/7064565.html

    總結(jié)

    以上是生活随笔為你收集整理的[设计模式][c++]状态切换模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。