(Boolan) C++設(shè)計模式 第三周筆記(二)

狀態(tài)模式
一、描述

概念:允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為。對象看起來似乎修改了它的類。

問題:
每個人、事物在不同的狀態(tài)下會有不同表現(xiàn)(動作),而一個狀態(tài)又會在不同的表現(xiàn)下轉(zhuǎn)移到下一個不同的狀態(tài)(State)。最簡單的一個生活中的例子就是:
地鐵入口處,如果你放入正確的地鐵票,門就會打開讓你通過。在出口處也是驗票,如果正確你就可以 ok,否則就不讓你通過(如果你動作野蠻,或許會有報警(Alarm),:)。

有限狀態(tài)自動機(jī)(FSM)也是一個典型的狀態(tài)不同,對輸入有不同的響應(yīng)(狀態(tài)轉(zhuǎn)移)。通常我們在實現(xiàn)這類系統(tǒng)會使用到很多的Switch/Case語句,Case某種狀態(tài),發(fā)生什么動作,Case 另外一種狀態(tài),則發(fā)生另外一種狀態(tài)。但是這種實現(xiàn)方式至少有以下兩個問題:
1)當(dāng)狀態(tài)數(shù)目不是很多的時候,Switch/Case 可能可以搞定。但是當(dāng)狀態(tài)數(shù)目很多的時候(實際系統(tǒng)中也正是如此),維護(hù)一大組的 Switch/Case 語句將是一件異常困難并且容易出錯的事情。
2)狀態(tài)邏輯和動作實現(xiàn)沒有分離。在很多的系統(tǒng)實現(xiàn)中,動作的實現(xiàn)代碼直接寫在狀態(tài)的邏輯當(dāng)中。這帶來的后果就是系統(tǒng)的擴(kuò)展性和維護(hù)得不到保證。

模式選擇

State 模式就是被用來解決上面列出的兩個問題的,在 State 模式中我們將狀態(tài)邏輯和動作實現(xiàn)進(jìn)行分離。當(dāng)一個操作中要維護(hù)大量的 case 分支語句,并且這些分支依賴于對象的狀態(tài)。State 模式將每一個分支都封裝到獨(dú)立的類中。

State 模式典型的結(jié)構(gòu)圖為:

備忘錄模式
一、描述:

  沒有人想犯錯誤,但是沒有人能夠不犯錯誤。犯了錯誤一般只能改過,卻很難改正(恢復(fù))。世界上沒有后悔藥,但是我們在進(jìn)行軟件系統(tǒng)的設(shè)計時候是要給用戶后悔的權(quán)利(實際上可能也是用戶要求的權(quán)利:),我們對一些關(guān)鍵性的操作肯定需要提供諸如撤銷(Undo) 的操作。那這個后悔藥就是 Memento 模式提供的。 

  Memento 模式的關(guān)鍵就是要在不破壞封裝行的前提下,捕獲并保存一個類的內(nèi)部狀態(tài),這樣就可以利用該保存的狀態(tài)實施恢復(fù)操作。為了達(dá)到這個目標(biāo),可以在后面的實現(xiàn)中看到我們采取了一定語言支持的技術(shù)。

**Memento 模式的典型結(jié)構(gòu)圖為: **

二、實例

備忘錄:Memento類
Memento.h

#ifndef __Memento__Memento__  
#define __Memento__Memento__  
  
#include <iostream>  
#include <string>   
using namespace std;  
  
class Memento  
{  
public:  
      
protected:  
      
private:  
    //這是最關(guān)鍵的地方,將 Originator 為 friend 類,可以訪問內(nèi)部信息,但是其他類不能訪問  
    friend class Originator; typedef string State;  
    Memento();  
    Memento(const State& sdt); ~Memento();  
    void SetState(const State& sdt); State GetState();  
      
private:  
    State _sdt;  
};  

Memento.cpp

#include "Memento.h"  
typedef string State;  
Memento::Memento()  
{  
}  
Memento::Memento(const State& sdt)  
{  
    this->_sdt = sdt;  
}  
State Memento::GetState()  
{  
    return this->_sdt;  
}  
void Memento::SetState(const State& sdt)  
{  
    this->_sdt = sdt;  
}  

撤銷返回操作:originator類
originator.h

#ifndef __Memento__Originator__  
#define __Memento__Originator__  
  
#include <iostream>  
#include <string>  
#include "Memento.h"  
using namespace std;  
class Originator  
{  
public:  
    typedef string State; Originator();  
    Originator(const State& sdt);  
    ~Originator();  
    Memento* CreateMemento();  
    void SetMemento(Memento* men);  
    void RestoreToMemento(Memento* mt);  
    State GetState();  
    void SetState(const State& sdt);  
    void PrintState();  
      
protected:  
private:  
    State _sdt;  
    Memento* _mt;  
};  

Originator.cpp


#include "Originator.h"  
typedef string State;  
  
Originator::Originator()  
{  
    this->_sdt = "";  
    this->_mt = 0;  
}  
Originator::Originator(const State& sdt)  
{  
    this->_sdt = sdt;  
    this->_mt = 0;  
}  
Originator::~Originator()  
{  
      
}  
  
Memento* Originator::CreateMemento()  
{  
    return new Memento(_sdt);  
}  
  
State Originator::GetState()  
{  
    return this->_sdt;  
}  
  
void Originator::SetState(const State& sdt)  
{  
    this->_sdt = sdt;  
}  
  
void Originator::PrintState()  
{  
    cout<<this->_sdt<<"....."<<endl;  
}  
  
void Originator::SetMemento(Memento* men)  
{  
      
}  
  
void Originator::RestoreToMemento(Memento* mt)  
{  
    this->_sdt = mt->GetState();  
}  

主程序:main
main.cpp

#include <iostream>  
#include "Memento.h"  
#include "Originator.h"  
using namespace std;  
  
int main(int argc, const char * argv[])  
{  
  
    // insert code here...  
    Originator *myOriginator = new Originator();  
    myOriginator->SetState("備忘狀態(tài)old");//備忘前狀態(tài)  
    myOriginator->PrintState();  
      
    Memento *myMemento = myOriginator->CreateMemento();//將狀態(tài)備忘  
      
    myOriginator->SetState("修改狀態(tài)new");//修改狀態(tài)  
    myOriginator->PrintState();  
    myOriginator->RestoreToMemento(myMemento);//恢復(fù)修改前狀態(tài)  
    myOriginator->PrintState();  
      
      
    std::cout << "Hello, World!\n";  
    return 0;  
}  

Memento 模式的關(guān)鍵就是 friend class Originator;我們可以看到,Memento 的接口都聲明為 private,而將 Originator 聲明為 Memento 的友元類。我們將 Originator 的狀態(tài)保存在 Memento 類中,而將 Memento 接口 private 起來,也就達(dá)到了封裝的功效。 在 Originator 類中我們提供了方法讓用戶后悔:RestoreToMemento(Memento* mt);我們可以 通過這個接口讓用戶后悔。在測試程序中,我們演示了這一點(diǎn):Originator 的狀態(tài)由 old 變?yōu)?new 最 后又回到了 old。

命令模式
一、描述:

  命令模式,將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進(jìn)行參數(shù)化;對請求排隊或記錄請求日志,以及支持可撤消的操作。應(yīng)該是一個比較簡單的模式了。

** Command 模式的典型結(jié)構(gòu)圖為: **

  Command 模式結(jié)構(gòu)圖中,將請求的接收者(處理者)放到 Command 的具體子類ConcreteCommand 中,當(dāng)請求到來時(Invoker 發(fā)出 Invoke 消息激活 Command 對象),ConcreteCommand 將處理請求交給 Receiver 對象進(jìn)行處理。 

二、實例:
描述:
今天講命令模式,這個模式從名字上看就很簡單,命令嘛,老大發(fā)命令,小兵執(zhí)行就是了,確實是這個意思,但是更深化了,用模式來描述真是是世界的命令情況。正在看這本書的你,我猜測分為兩類:已經(jīng)工作的和沒有工作的,先說沒有工作的,那你為啥要看這本書,為了以后工作唄,只要你參見工作,你肯定會待在項目組,那今天我們就以項目組為例子來講述命令模式。
我是我們部門的項目經(jīng)理,就是一個項目的頭,在中國做項目,項目經(jīng)理就是什么都要懂,什么都要管,做好了項目經(jīng)理能分到一杯羹,做不好都是你項目經(jīng)理的責(zé)任,這個是絕對的,我?guī)н^太多的項目,行政命令一壓下來,那就一條道,做完做好!我們雖然是一個集團(tuán)公司,但是我們部門是獨(dú)立核算的,就是說呀,我們部門不僅僅為我們集團(tuán)服務(wù),還可以為其他甲方服務(wù),賺取更多的外快,所以俺們的工資才能是中上等。在 2007 年我?guī)ьI(lǐng)了一個項目,比較小,但是錢可不少,是做什么的呢?為一家旅行社建立一套內(nèi)部管理系統(tǒng),管理他的客戶、旅游資源、票務(wù)以及內(nèi)部管理,整體上類似一個小型的 ERP 系統(tǒng),門店比較多,員工也比較多,但是需求比較明確,因為他們之前有一套自己購買的內(nèi)部管理系統(tǒng),這次變動部分模塊基本上是翻版,而且旅行社有自己的IT 部門,比較好相處,都是技術(shù)人員,沒有交流鴻溝嘛。
這個項目的成員分工也是采用了常規(guī)的分工方式,分為需求組(Requirement Group,簡稱 RG)、美工組(Page Group,簡稱 PG)、代碼組(我們內(nèi)部還有一個比較優(yōu)雅的名字:邏輯實現(xiàn)組,這里使用大家經(jīng)常稱呼的名稱吧,英文縮寫叫 Code Group,簡稱 CG),總共加上我這個項目經(jīng)理正好十個人,剛開始的時候客戶(也就是旅行社,甲方)還是很樂意和我們每個組探討,比如和需求組討論需求,和美工討論頁面,和代碼組討論實現(xiàn),告訴他們修改這里,刪除這里,增加這些等等,這是一種比較常見的甲乙方合作模式,甲方深入到乙方的項目開發(fā)中,我們把這個模式用類圖表示一下:

但是問題來了,我們修改可以,但是每次都是叫一個組去,布置個任務(wù),然后出計劃,次次都這樣,如果讓你當(dāng)甲方也就是客戶,你煩不煩?而且這種方式很容易出錯誤呀,而且還真發(fā)生過,客戶把美工叫過去了,要刪除,可美工說需求是這么寫的,然后客戶又命令需求組過去,一次次的折騰,客戶也煩躁了,于是直接抓住我這個項目經(jīng)理說:
“我不管你們內(nèi)部怎么安排,你就給我找個接頭人,我告訴他怎么做,刪除頁面了,增加功能了,你們內(nèi)部 怎么處理,我就告訴他我要干什么就成了...”我一聽,好呀,這也正是我想要的,我項目組的兄弟們也已經(jīng)受不了了,于是我改變了一下我的處理方式, 看看類圖(類圖稍微更改下名稱):

注釋:

main(),客戶
Invoker,命令接收者,如項目經(jīng)理
IGroup,執(zhí)行者接口
CRequirementGroup,需要組
CPageGroup,美工組
CCodePage,代碼組
ICommand,命令接口
CAddRequirementCommand,執(zhí)行增加一項需求的命令(Execute函數(shù),將調(diào)用CRequirementGroup的多個命令。來組合執(zhí)行用戶發(fā)出的命令。)
CDeletePageCommand,執(zhí)行刪除一個頁面的命令

命令接收者:InvokerInvoker.h

#ifndef __Command__Invoker__  
#define __Command__Invoker__  
  
#include <iostream>  
#include "ICommand.h"  
  
class CInvoker  
{  
public:  
    CInvoker(void);  
    ~CInvoker(void);  
    void SetCommand(ICommand *pcommand);  
    void Action();  
private:  
    ICommand *m_pCommand;  
};  
  

Invoker.cpp

#include "Invoker.h"  
CInvoker::CInvoker(void)  
{  
}  
CInvoker::~CInvoker(void)  
{  
}  
void CInvoker::SetCommand( ICommand *pcommand )  
{  
    this->m_pCommand = pcommand;  
}  
void CInvoker::Action()  
{  
    this->m_pCommand->Execute();  
}  

命令接口:IComman類
ICommand.h


#ifndef Command_ICommand_h  
#define Command_ICommand_h  
#include "RequirementGroup.h"  
#include "PageGroup.h"  
#include "CodeGroup.h"  
  
class ICommand {     
public:  
      
    ICommand(void)  
    {  
        m_prg = new CRequirementGroup();  
        m_ppg = new CPageGroup();  
        m_pcg = new CCodeGroup();  
    }  
    virtual ~ICommand(void)  
    {  
        delete m_prg;  
        delete m_ppg;  
        delete m_pcg;  
    }  
    virtual void Execute() = 0;  
      
protected:  
      
    CRequirementGroup *m_prg;  
    CPageGroup *m_ppg;  
    CCodeGroup *m_pcg;  
      
};  
  

執(zhí)行增加一項需求的命令:CAddRequirementCommand類
CAddRequirementCommand.h


#ifndef __Command__AddRequirementCommand__  
#define __Command__AddRequirementCommand__  
  
#include <iostream>  
#include "ICommand.h"  
class CAddRequirementCommand :public ICommand  
{  
public:  
    CAddRequirementCommand(void);  
    ~CAddRequirementCommand(void);  
    void Execute();  
};  
  

AddRequirementCommand.cpp

#include "AddRequirementCommand.h"  
  
CAddRequirementCommand::CAddRequirementCommand(void)  
{  
}  
CAddRequirementCommand::~CAddRequirementCommand(void)  
{  
}  
void CAddRequirementCommand::Execute()  
{  
    //執(zhí)行增另一項需求的命令  
    this->ICommand::m_prg->Find();  
      
    //增加一份需求  
    this->ICommand::m_prg->Add();  
      
    //給出計劃  
    this->ICommand::m_prg->Plan();  
}  

執(zhí)行刪除一個頁面的命令 :CDeletePageCommand類
CDeletePageCommand.h


#ifndef __Command__DeletePageCommand__  
#define __Command__DeletePageCommand__  
  
#include <iostream>  
#include "ICommand.h"  
  
class CDeletePageCommand :  
public ICommand  
{  
public:  
    CDeletePageCommand(void);  
    ~CDeletePageCommand(void);  
    void Execute();  
};  
  

DeletePageCommand.cpp

**[cpp]** [view plain](http://blog.csdn.net/rexuefengye/article/details/13004205#) [copy](http://blog.csdn.net/rexuefengye/article/details/13004205#)

#include "DeletePageCommand.h"  
  
CDeletePageCommand::CDeletePageCommand(void)  
{  
}  
CDeletePageCommand::~CDeletePageCommand(void)  
{  
}  
void CDeletePageCommand::Execute()  
{  
    //執(zhí)行增另一項需求的命令  
    this->ICommand::m_ppg->Find();  
      
    //增加一份需求  
    this->ICommand::m_ppg->Delete();  
      
    //給出計劃  
    this->ICommand::m_ppg->Plan();  
}  

執(zhí)行者接口:IGroup
IGroup.h

#ifndef Command_IGroup_h  
#define Command_IGroup_h  
class IGroup  
{  
public:  
    IGroup(void){}  
    virtual ~IGroup(void){}  
    virtual void Find() = 0;  
    virtual void Add() = 0;  
    virtual void Delete() = 0;  
    virtual void Change() = 0;  
    virtual void Plan() = 0;  
};  

需要組:CRequirementGroup類
CRequirementGroup.h

#ifndef __Command__RequirementGroup__  
#define __Command__RequirementGroup__  
  
#include <iostream>  
#include "IGroup.h"  
class CRequirementGroup:public IGroup  
{  
public:  
    CRequirementGroup(void);  
    ~CRequirementGroup(void);  
    void Find();  
    void Add();  
    void Delete();  
    void Change();  
    void Plan();  
};  
  
  

CRequirementGroup.cpp

#include "RequirementGroup.h"  
using std::cout;  
using std::endl;  
  
CRequirementGroup::CRequirementGroup(void)  
{  
}  
CRequirementGroup::~CRequirementGroup(void)  
{  
}  
void CRequirementGroup::Find()  
{  
    cout << "找到需求組..." << endl;  
}  
void CRequirementGroup::Add()  
{  
    cout << "客戶要求增加一項需求..." << endl;  
}  
void CRequirementGroup::Delete()  
{  
    cout << "要求刪除一項需求..." << endl;  
}  
void CRequirementGroup::Change()  
{  
    cout << "客戶要求修改一項需求..." << endl;  
}  
void CRequirementGroup::Plan()  
{  
    cout << "客戶要求需求變更計劃..." << endl;  
}  

美工組:CPageGroup
CPageGroup.h


#ifndef __Command__CPageGroup__  
#define __Command__CPageGroup__  
  
#include <iostream>  
#include "IGroup.h"  
  
class CPageGroup :public IGroup  
{  
public:  
    CPageGroup(void);  
    ~CPageGroup(void);  
    void Find();  
    void Add();  
    void Delete();  
    void Change();  
    void Plan();  
};  
  

CPageGroup.cpp

#include "PageGroup.h"  
  
using std::cout;  
using std::endl;  
CPageGroup::CPageGroup(void)  
{  
}  
  
CPageGroup::~CPageGroup(void)  
{  
}  
  
void CPageGroup::Find()  
{  
    cout << "找到美工組..." << endl;  
}  
  
void CPageGroup::Add()  
{  
    cout << "客戶要求增加一個頁面..." << endl;  
}  
  
void CPageGroup::Delete()  
{  
    cout << "客戶要求刪除一個頁面..." << endl;  
}  
  
void CPageGroup::Change()  
{  
    cout << "客戶要求修改一個頁面..." << endl;  
}  
  
void CPageGroup::Plan()  
{  
    cout << "客戶要求頁面變更計劃..." << endl;  
}  

代碼組:CCodePage
CCodePage.h


#ifndef __Command__CodeGroup__  
#define __Command__CodeGroup__  
  
#include <iostream>  
#include "IGroup.h"  
  
class CCodeGroup :public IGroup  
{  
public:  
    CCodeGroup(void);  
    ~CCodeGroup(void);  
    void Find();  
    void Add();  
    void Delete();  
    void Change();  
    void Plan();  
};  

CCodePage.cpp


#include "CodeGroup.h"  
using std::cout;  
using std::endl;  
  
CCodeGroup::CCodeGroup(void)  
{  
}  
  
CCodeGroup::~CCodeGroup(void)  
{  
}  
  
void CCodeGroup::Find()  
{  
    cout << "找到代碼組..." << endl;  
}  
  
void CCodeGroup::Add()  
{  
    cout << "客戶要求增加一項功能..." << endl;  
}  
  
void CCodeGroup::Delete()  
{  
    cout << "客戶要求刪除一項功能..." << endl;  
}  
  
void CCodeGroup::Change()  
{  
    cout << "客戶要求修改一項功能..." << endl;  
}  
  
void CCodeGroup::Plan()  
{  
    cout << "客戶要求代碼變更計劃..." << endl;  
}  

客戶 :main
main.cpp


#include <iostream>  
#include "IGroup.h"  
#include "ICommand.h"  
#include "RequirementGroup.h"  
#include "PageGroup.h"  
#include "CodeGroup.h"  
#include "AddRequirementCommand.h"  
#include "DeletePageCommand.h"  
#include "Invoker.h"  
using std::cout;  
using std::endl;  
  
void DoIt()  
{  
    cout << "----------客戶想增加一個需求----------" << endl;  
    IGroup *rg = new CRequirementGroup();  
    rg->Find();  
    rg->Add();  
    rg->Plan();  
    delete rg;  
    cout << endl;  
      
    cout << "----------客戶又想修改一個頁面----------" << endl;  
    IGroup *pg = new CPageGroup();  
    pg->Find();  
    pg->Add();  
    pg->Plan();  
    delete pg;  
    cout << endl;  
      
    cout << "----------客戶又想刪除一個功能----------" << endl;  
    IGroup *cg = new CCodeGroup();  
    cg->Find();  
    cg->Add();  
    cg->Plan();  
    delete cg;  
    cout << endl;  
}  
  
void DoNew()  
{  
    cout << "----------客戶覺得煩了,希望只找一個人,并告訴他要做什么----------" << endl;  
    cout << "----------客戶要求增加一項需求----------" << endl;  
    CInvoker gary;  
    ICommand *pcommand = new CAddRequirementCommand();  
    gary.SetCommand(pcommand);  
    gary.Action();  
    delete pcommand;  
    cout << endl;  
      
    //客戶想要改動只需要找CInvoker就可以了。  
    cout << "----------客戶要求刪除一個頁面----------" << endl;  
    CInvoker ricky;  
    ICommand *pcommand2 = new CDeletePageCommand();  
    ricky.SetCommand(pcommand2);  
    ricky.Action();  
    delete pcommand2;  
    cout << endl;  
}  
  
  
int main(int argc, const char * argv[])  
{  
    //客戶原來的運(yùn)行流程  
    cout<<"客戶原來的運(yùn)行流程"<<endl;  
    DoIt();  
      
    //客戶覺得麻煩了,每次改動都要找不同的組,談不同的事  
    //客戶只想找一個人,告訴他要做什么就可以,不想關(guān)心由哪幾個組來做和怎么做  
    cout<<"********************命令模式********************"<<endl;  
    DoNew();  
    // insert code here...  
    std::cout << "Hello, World!\n";  
    return 0;  
}  

結(jié)果如下:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容