美文网首页
(Boolan) C++设计模式 第三周笔记(二)

(Boolan) C++设计模式 第三周笔记(二)

作者: 卡尔曼 | 来源:发表于2017-12-26 12:57 被阅读0次

    状态模式

    一、描述

    概念:允许一个对象在其内部状态改变时改变它的行为。 对象看起来似乎修改了它的类。

    问题:

    每个人、事物在不同的状态下会有不同表现(动作),而一个状态又会在不同的表现下转移到下一个不同的状态(State)。 最简单的一个生活中的例子就是:

    地铁入口处,如果你放入正确的地铁票,门就会打开让你通过。 在出口处也是验票,如果正确你就可以 ok,否则就不让你通过(如果你动作野蛮,或许会有报警(Alarm),:)。

    有限状态自动机(FSM)也是一个典型的状态不同,对输入有不同的响应(状态转移)。 通常我们在实现这类系统会使用到很多的Switch/Case语句,Case某种状态,发生什么动作,Case 另外一种状态,则发生另外一种状态。 但是这种实现方式至少有以下两个问题:

    1)当状态数目不是很多的时候,Switch/Case 可能可以搞定。 但是当状态数目很多的时候(实际系统中也正是如此),维护一大组的 Switch/Case 语句将是一件异常困难并且容易出错的事情。

    2)状态逻辑和动作实现没有分离。 在很多的系统实现中,动作的实现代码直接写在状态的逻辑当中。 这带来的后果就是系统的扩展性和维护得不到保证。

    模式选择

    State 模式就是被用来解决上面列出的两个问题的,在 State 模式中我们将状态逻辑和动作实现进行分离。 当一个操作中要维护大量的 case 分支语句,并且这些分支依赖于对象的状态。 State 模式将每一个分支都封装到独立的类中。

    State 模式典型的结构图为:

    备忘录模式

    一、描述:

      没有人想犯错误,但是没有人能够不犯错误。犯了错误一般只能改过,却很难改正(恢复)。世界上没有后悔药,但是我们在进行软件系统的设计时候是要给用户后悔的权利(实际上可能也是用户要求的权利:),我们对一些关键性的操作肯定需要提供诸如撤销(Undo) 的操作。那这个后悔药就是 Memento 模式提供的。

      Memento 模式的关键就是要在不破坏封装行的前提下,捕获并保存一个类的内部状态,这样就可以利用该保存的状态实施恢复操作。为了达到这个目标,可以在后面的实现中看到我们采取了一定语言支持的技术。

    **Memento 模式的典型结构图为: **

    二、实例

    备忘录:Memento类

    Memento.h

    #ifndef __Memento__Memento__ 

    #define __Memento__Memento__ 

    #include  

    #include  

    using namespace std; 

    class Memento 

    public: 

    protected: 

    private: 

        //这是最关键的地方,将 Originator 为 friend 类,可以访问内部信息,但是其他类不能访问 

        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  

    #include  

    #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<_sdt<<"....."<

    void Originator::SetMemento(Memento* men) 

    void Originator::RestoreToMemento(Memento* mt) 

        this->_sdt = mt->GetState(); 

    主程序:main

    main.cpp

    #include  

    #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("备忘状态old");//备忘前状态 

        myOriginator->PrintState(); 

        Memento *myMemento = myOriginator->CreateMemento();//将状态备忘 

        myOriginator->SetState("修改状态new");//修改状态 

        myOriginator->PrintState(); 

        myOriginator->RestoreToMemento(myMemento);//恢复修改前状态 

        myOriginator->PrintState(); 

        std::cout << "Hello, World!\n"; 

        return 0; 

    Memento 模式的关键就是 friend class Originator;我们可以看到,Memento 的接口都声明为 private,而将 Originator 声明为 Memento 的友元类。 我们将 Originator 的状态保存在 Memento 类中,而将 Memento 接口 private 起来,也就达到了封装的功效。 在 Originator 类中我们提供了方法让用户后悔:RestoreToMemento(Memento* mt);我们可以 通过这个接口让用户后悔。 在测试程序中,我们演示了这一点:Originator 的状态由 old 变为 new 最 后又回到了 old。

    命令模式

    一、描述:

      命令模式,将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。应该是一个比较简单的模式了。

    ** Command 模式的典型结构图为: **

      Command 模式结构图中,将请求的接收者(处理者)放到 Command 的具体子类ConcreteCommand 中,当请求到来时(Invoker 发出 Invoke 消息激活 Command 对象),ConcreteCommand 将处理请求交给 Receiver 对象进行处理。

    二、实例:

    描述:

    今天讲命令模式,这个模式从名字上看就很简单,命令嘛,老大发命令,小兵执行就是了,确实是这个意思,但是更深化了,用模式来描述真是是世界的命令情况。 正在看这本书的你,我猜测分为两类:已经工作的和没有工作的,先说没有工作的,那你为啥要看这本书,为了以后工作呗,只要你参见工作,你肯定会待在项目组,那今天我们就以项目组为例子来讲述命令模式。

    我是我们部门的项目经理,就是一个项目的头,在中国做项目,项目经理就是什么都要懂,什么都要管,做好了项目经理能分到一杯羹,做不好都是你项目经理的责任,这个是绝对的,我带过太多的项目,行政命令一压下来, 那就一条道,做完做好!我们虽然是一个集团公司,但是我们部门是独立核算的,就是说呀,我们部门不仅仅为我们集团服务,还可以为其他甲方服务,赚取更多的外快,所以俺们的工资才能是中上等。 在 2007 年我带领了一个项目,比较小,但是钱可不少,是做什么的呢?为一家旅行社建立一套内部管理系统,管理他的客户、旅游资源、票务以及内部管理,整体上类似一个小型的 ERP 系统,门店比较多,员工也比较多,但是需求比较明确, 因为他们之前有一套自己购买的内部管理系统,这次变动部分模块基本上是翻版,而且旅行社有自己的IT 部门,比较好相处,都是技术人员,没有交流鸿沟嘛。

    这个项目的成员分工也是采用了常规的分工方式,分为需求组(Requirement Group,简称 RG)、美工组(Page Group,简称 PG)、代码组(我们内部还有一个比较优雅的名字:逻辑实现组, 这里使用大家经常称呼的名称吧,英文缩写叫 Code Group,简称 CG),总共加上我这个项目经理正好十个人,刚开始的时候客户(也就是旅行社,甲方)还是很乐意和我们每个组探讨,比如和需求组讨论需求,和美工讨论页面, 和代码组讨论实现,告诉他们修改这里,删除这里,增加这些等等,这是一种比较常见的甲乙方合作模式,甲方深入到乙方的项目开发中,我们把这个模式用类图表示一下:

    但是问题来了,我们修改可以,但是每次都是叫一个组去,布置个任务,然后出计划,次次都这样,如果让你当甲方也就是客户,你烦不烦?而且这种方式很容易出错误呀,而且还真发生过,客户把美工叫过去了,要删除,可美工说需求是这么写的, 然后客户又命令需求组过去,一次次的折腾,客户也烦躁了,于是直接抓住我这个项目经理说:

    “我不管你们内部怎么安排,你就给我找个接头人,我告诉他怎么做,删除页面了,增加功能了,你们内部 怎么处理, 我就告诉他我要干什么就成了...”我一听,好呀,这也正是我想要的,我项目组的兄弟们也已经受不了了,于是我改变了一下我的处理方式, 看看类图(类图稍微更改下名称):

    注释:

    main(),客户

    Invoker,命令接收者,如项目经理

    IGroup,执行者接口

    CRequirementGroup,需要组

    CPageGroup,美工组

    CCodePage,代码组

    ICommand,命令接口

    CAddRequirementCommand,执行增加一项需求的命令( Execute函数,将调用CRequirementGroup的多个命令。 来组合执行用户发出的命令。 )

    CDeletePageCommand,执行删除一个页面的命令

    命令接收者:InvokerInvoker.h

    #ifndef __Command__Invoker__ 

    #define __Command__Invoker__ 

    #include  

    #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; 

    }; 

    执行增加一项需求的命令:CAddRequirementCommand类

    CAddRequirementCommand.h

    #ifndef __Command__AddRequirementCommand__ 

    #define __Command__AddRequirementCommand__ 

    #include  

    #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() 

        //执行增另一项需求的命令 

        this->ICommand::m_prg->Find(); 

        //增加一份需求 

        this->ICommand::m_prg->Add(); 

        //给出计划 

        this->ICommand::m_prg->Plan(); 

    执行删除一个页面的命令 :CDeletePageCommand类

    CDeletePageCommand.h

    #ifndef __Command__DeletePageCommand__ 

    #define __Command__DeletePageCommand__ 

    #include  

    #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() 

        //执行增另一项需求的命令 

        this->ICommand::m_ppg->Find(); 

        //增加一份需求 

        this->ICommand::m_ppg->Delete(); 

        //给出计划 

        this->ICommand::m_ppg->Plan(); 

    执行者接口: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  

    #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  

    #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  

    #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  

    #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[]) 

        //客户原来的运行流程 

        cout<<"客户原来的运行流程"<

        DoIt(); 

        //客户觉得麻烦了,每次改动都要找不同的组,谈不同的事 

        //客户只想找一个人,告诉他要做什么就可以,不想关心由哪几个组来做和怎么做 

        cout<<"********************命令模式********************"<

        DoNew(); 

        // insert code here... 

        std::cout << "Hello, World!\n"; 

        return 0; 

    结果如下:

    相关文章

      网友评论

          本文标题:(Boolan) C++设计模式 第三周笔记(二)

          本文链接:https://www.haomeiwen.com/subject/cugdgxtx.html