学习记录:《C++设计模式——李建忠主讲》6.“状态变化”模式

状态变化模式:在组件构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定。状态变化模式为这一问题提供了一种解决方案。

典型模式:状态模式(State)、备忘录模式(Memento)

一、状态模式

1.动机

在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生改变,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同。

2.作用

在运行时根据对象的状态来透明地更改对象的行为,而不会为对象操作和状态转化之间引入紧耦合。

3.定义

允许一个对象在其内部状态发生改变时改变它的行为,从而使对象看起来似乎修改了其行为。

4.代码

//原有代码
enum NetworkState
{
    Network_Open,
    Network_Close,
    Network_Connect,
};
class NetworkProcessor{  
    NetworkState state;
public: 
    void Operation1(){
        if (state == Network_Open){
            //**********
            state = Network_Close;
        }
        else if (state == Network_Close){
            //..........
            state = Network_Connect;
        }
        else if (state == Network_Connect){
            //$$$$$$$$$$
            state = Network_Open;
        }
    }
    public void Operation2(){
        if (state == Network_Open){
            //**********
            state = Network_Connect;
        }
        else if (state == Network_Close){
            //.....
            state = Network_Open;
        }
        else if (state == Network_Connect){
            //$$$$$$$$$$
            state = Network_Close;
        }
    }
    public void Operation3(){
        //**********
    }
};
//运用状态模式后代码
class NetworkState{
public:
    NetworkState* pNext;
    virtual void Operation1()=0;
    virtual void Operation2()=0;
    virtual void Operation3()=0;
    virtual ~NetworkState(){}
};
class OpenState :public NetworkState{   
    static NetworkState* m_instance;
public:
    static NetworkState* getInstance(){
        //某个对象任何情况下应该只有一种状态,
        //故采用单件模式使状态唯一
        if (m_instance == nullptr) {
            m_instance = new OpenState();
        }
        return m_instance;
    }
    void Operation1(){  
        //**********   open状态下的行为1
        pNext = CloseState::getInstance();
    }
    void Operation2(){
        //..........
        pNext = ConnectState::getInstance();
    }
    void Operation3(){
        //$$$$$$$$$$
        pNext = OpenState::getInstance();
    }
};
//关闭状态和连接状态 略写
class CloseState:public NetworkState{ }
class ConnectState:public NetworkState{ }

class NetworkProcessor{
    NetworkState* pState;
public: 
    NetworkProcessor(NetworkState* pState){  
        this->pState = pState;
    }
    void Operation1(){
        //...
        pState->Operation1();
        pState = pState->pNext;
        //...
    }
    void Operation2(){
        //...
        pState->Operation2();
        pState = pState->pNext;
        //...
    }
    void Operation3(){
        //...
        pState->Operation3();
        pState = pState->pNext;
        //...
    }
};

5.解析

        这是一个表示网络行为的设计。网络对象有三种不同状态,open、close、connect。当网络对象收到其他对象的请求时,它根据自身当前状态做出不同的反应。例如,行为1的请求会让open状态变为close。

        在状态模式中,引入了一个称为NetworkState的抽象类来表示网络的连接状态。NetworkState类为各不同操作状态的子类声明了一个公共接口。NetworkState子类实现与特定状态相关的行为。

        NetworkProcessor类维护了NetWork连接状态对象,一旦状态改变,NetworkProcessor就会改变它使用的状态对象,所调用的NetWorkState类子类也会随之改变。

6.结构

其中,

        1.Context(环境,如NetworkProcessor):定义客户感兴趣的接口;维护一个ConcreteState子类的实例,这个实例定义为当前状态;

        2.State(状态,如NetworkState):定义一个接口以封装与Context的特定状态相关的行为;

        3.ConcreteState(具体状态子类,如OpenState等):每一个子类实现一个与Context的一个状态相关的行为。

7.总结   

        1.State模式将所有与一个特定状态相关的行为都放入一个State的子类对象中,在对象状态切换时,切换相应的对象,但同时维持State的接口,这样实现了具体操作与状态转换之间的解耦。

        2.为不同的状态引入不同的对象使得状态转换变得更加明确,而且可以保证不会出现状态不一致的情况,因为转换是原子性的——即要么彻底转换过来,要么不转换。

        3.如果State对象没有实例实例变量,那么各个上下文可以共享同一个State对象,从而节省对象开销。

二、备忘录模式

1.动机

在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前某个点时的状态。如果使用一些公有接口来让其他对象得到对象的状态,便会暴露对象的细节实现。

2.作用

既能实现对象状态的良好保存与恢复,但同时又不会因此而破坏对象本身的封装性。

3.定义

在不破坏对象封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。

4.代码

//备忘录模式实现
class Memento
{
    string state;
    //..
public:
    Memento(const string & s) : state(s) {}
    string getState() const { return state; }
    void setState(const string & s) { state = s; }
};
class Originator
{
    string state;
    //....
public:
    Originator() {}
    Memento createMomento() {
        Memento m(state);
        return m;
    }
    void setMomento(const Memento & m) {
        state = m.getState();
    }
};
int main()
{
    Originator orginator;
    //捕获对象状态,存储到备忘录
    Memento mem = orginator.createMomento();
    //... 改变orginator状态

    //从备忘录中恢复
    orginator.setMomento(memento); 
}

5.解析 

        考虑一个图形编辑器,它支持图形对象之间的连线,而需要保证能撤销操作。

        我们可用备忘录模式解决这一问题。一个备忘录是一个对象,它存储另一个对象在某个瞬间的内部状态,而后者称为备忘录的原发器。当需要设置原发器的检查点时,取消操作机制会向原发器请求一个备忘录。原发器用描述当前状态的信息初始化备忘录。只有原发器可以向备忘录中存取信息,备忘录对其他对象“不可见”。

 6.结构

其中,     

        1.Memento(备忘录):存储原发器对象的内部状态。原发器对象根据需要决定备忘录存储原发器的哪些内部对象;防止原发器以为的对象访问备忘录。

        2.Originator(原发器):原发器创建一个备忘录,用于记录当前时刻它的内部状态;使用备忘录恢复内部状态;

        3.Caretaker(负责人,如main函数):负责保存好备忘录,但不能对备忘录的内容进行操作或检查。

7.总结

        1.备忘录(Memento)存储原发器(Originator)对象的内部状态,在需要时恢复原发器状态。

        2. Memento模式的核心是信息隐藏,即Originator需要向外接隐藏信息,保持其封装性。但同时需要将状态保持到外界(Memento)。

猜你喜欢

转载自www.cnblogs.com/gql-live-laugh-love/p/11922509.html
今日推荐