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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

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

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

轉自:http://blog.csdn.net/yongh701/article/details/49154439

?

狀態模式也是設計模式的一種,這種設計模式思想不復雜,就是實現起來的代碼有點復雜。主要出現在類傳遞參數上,尤其是C++這種不能直接類間互相調用都語言,實現狀態模式更難,當然,一切設計模式都是為了更簡短的主函數。

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

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

說是這樣的意思:

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

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

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

?

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

  • 運行結果如下圖:

    ?

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

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

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

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

    題目是這樣的:

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

    ?

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

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

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

    ?

    [cpp]?view plaincopy print?
  • #include<iostream>??
  • using?namespace?std;??
  • //以下為類的定義部分??
  • class?TissueMachine;//類的提前引用??
  • //抽象狀態??
  • class?State{??
  • public:??
  • ????virtual?void?insertQuarter()=0;//“投幣”按鈕被按下??
  • ????virtual?void?ejectQuarter()=0;//“退幣”按鈕被按下??
  • ????virtual?void?turnCrank()=0;//“出紙巾”按鈕被按下??
  • ????virtual?void?dispense()=0;//正在賣出紙巾??
  • };??
  • ??
  • //具體狀態??
  • class?SoldOutState:public?State{//紙巾售完狀態??
  • private:??
  • ????TissueMachine*?tissueMachine;??
  • public:??
  • ????SoldOutState(TissueMachine?*tissueMachine){??
  • ????????this->tissueMachine=tissueMachine;??
  • ????}??
  • ????void?insertQuarter();??
  • ????void?ejectQuarter();??
  • ????void?turnCrank();??
  • ????void?dispense();??
  • };??
  • class?NoQuarterState:public?State{//沒有投幣狀態??
  • private:??
  • ????TissueMachine*?tissueMachine;??
  • public:??
  • ????NoQuarterState(TissueMachine?*tissueMachine){??
  • ????????this->tissueMachine=tissueMachine;??
  • ????}??
  • ????void?insertQuarter();??
  • ????void?ejectQuarter();??
  • ????void?turnCrank();??
  • ????void?dispense();??
  • };??
  • class?HasQuarterState:public?State{//有2元錢(已投幣狀態)??
  • private:??
  • ????TissueMachine*?tissueMachine;??
  • public:??
  • ????HasQuarterState(TissueMachine?*tissueMachine){??
  • ????????this->tissueMachine=tissueMachine;??
  • ????}??
  • ????void?insertQuarter();??
  • ????void?ejectQuarter();??
  • ????void?turnCrank();??
  • ????void?dispense();??
  • };??
  • class?SoldState:public?State{//出售紙巾狀態??
  • 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;//紙巾數??
  • public:??
  • ????TissueMachine(int?numbers){//構造函數,定義初始狀態有紙巾售賣機有多少紙巾??
  • ????????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;//開始為沒有投幣的狀態??
  • ????????}??
  • ????};??
  • ????//開放給主函數調用的方法??
  • ????void?insertQuarter(){??
  • ????????state->insertQuarter();??
  • ????}??
  • ????void?ejectQuarter(){??
  • ????????state->ejectQuarter();??
  • ????}??
  • ????void?turnCrank(){??
  • ????????state->turnCrank();??
  • ????????state->dispense();??
  • ????}??
  • ????//數據傳遞的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;??
  • ????};??
  • };??
  • ??
  • //具體狀態中各個方法的具體實現。??
  • //紙巾售完狀態??
  • void?SoldOutState::insertQuarter(){???????
  • ????cout<<"機器無紙巾,已退回硬幣!"<<endl;??
  • }??
  • void?SoldOutState::ejectQuarter(){??
  • ????cout<<"自動售貨機根本沒有硬幣!"<<endl;??
  • }??
  • void?SoldOutState::turnCrank(){??
  • ????cout<<"機器無紙巾,請不要操作機器"<<endl;??
  • }??
  • void?SoldOutState::dispense(){??
  • }??
  • //沒有投幣狀態??
  • void?NoQuarterState::insertQuarter(){?????????
  • ????tissueMachine->setState(tissueMachine->getHasQuarterState());??
  • ????cout<<"已投幣!"<<endl;??
  • }??
  • void?NoQuarterState::ejectQuarter(){??
  • ????cout<<"自動售貨機根本沒有硬幣!"<<endl;??
  • }??
  • void?NoQuarterState::turnCrank(){??
  • ????cout<<"請投幣"<<endl;??
  • }??
  • void?NoQuarterState::dispense(){??
  • }??
  • //有2元錢(已投幣狀態)??
  • void?HasQuarterState::insertQuarter(){??
  • ????cout<<"已投幣!請不要重復投幣!已退回重復投幣!"<<endl;??
  • }??
  • void?HasQuarterState::ejectQuarter(){??
  • ????tissueMachine->setState(tissueMachine->getNoQuarterState());??
  • ????cout<<"已取幣!"<<endl;??
  • }??
  • void?HasQuarterState::turnCrank(){??
  • ????tissueMachine->setState(tissueMachine->getSoldState());??
  • ????cout<<"請等待自動售貨機出紙巾!"<<endl;??
  • }??
  • void?HasQuarterState::dispense(){??
  • }??
  • //出售紙巾狀態??
  • void?SoldState::insertQuarter(){??
  • ????cout<<"請等待自動售貨機出紙巾!請不要投幣!已退回投幣!"<<endl;??
  • }??
  • void?SoldState::ejectQuarter(){??
  • ????tissueMachine->setState(tissueMachine->getNoQuarterState());??
  • ????cout<<"請等待自動售貨機出紙巾!無法取回已消費的硬幣!"<<endl;??
  • }??
  • void?SoldState::turnCrank(){??
  • ????cout<<"請等待自動售貨機出紙巾!已響應你的操作!"<<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;??
  • ????}??
  • }?????
  • //主函數??
  • int?main(){??
  • ????TissueMachine?*tissueMachine=new?TissueMachine(1);??
  • ????cout<<"紙巾數:"<<tissueMachine->getCount()<<endl;??
  • ????tissueMachine->insertQuarter();//投幣??
  • ????tissueMachine->turnCrank();//取紙巾??
  • ????cout<<"紙巾數:"<<tissueMachine->getCount()<<endl;//不投幣取紙巾測試??
  • ????tissueMachine->turnCrank();???
  • ????cout<<"紙巾數:"<<tissueMachine->getCount()<<endl;//售完紙巾,投幣取紙巾測試??
  • ????tissueMachine->insertQuarter();????
  • ????tissueMachine->turnCrank();???
  • ????return?0;??
  • }??

  • 運行結果如下:

    ?

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

    轉載于:https://www.cnblogs.com/lyggqm/p/7064565.html

    總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。