设计模式之“状态变化“模式:State、Memento


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



1. State 状态模式


1.1 State 状态模式动机

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

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


1.2 模式定义

允许一个对象在其内部状态改变时改变它的行为(运用运行时多态,类的virtual函数)。从而使对象看起来似乎修改了其行为。

Strategy 策略模式 的形式类同,同时对于没有实例变量成员的状态类型,可以多个对象享有同一个状态对象,所以 Singleton 单例模式 也常常伴随使用。
在这里插入图片描述


1.3 实例代码

在网络编程中,经常涉及到接口编程,每个接口都有打开、关闭、连接等状态,每种状态对应着不同的行为,例子按此场景展开。

在 State1.cpp 中,又见到了熟悉的枚举类型和if-else结构,此时就能够想到 Strategy策略模式 的使用场景,将 枚举类型 NetworkStatue -> 抽象基类,再将枚举类型中的 枚举常量(Network_Open, Network_Close, Network_Connect) -> 抽象基类的派生子类(枚举类型的相关定义和知识见:enum枚举类型用法) ,重载抽象基类中所继承的 Operation() 操作函数。

再将客户对象 NetworkProcesser类定义中的 if-else结构去掉,新增一NetState抽象基类指针,在Operation()中使用该指针调用相应的operation()操作,即可实现 NetwordStatue 的行为随其中状态的变化而变化的模式定义,具体代码见 State2.cpp。

同时看到 NetworkState 中没有实例变量,所以对其使用单例模式可以提高程序性能,减少内存消耗。

State1.cpp
State2.cpp

1.4 要点总结

  • State 模式将所有与一个特定状态相关的行为都放入一个 State的子类对象当中,在对象状态切换时,切换相应的对象;但同时维持 State 的接口,这样实现了 具体操作 和 状态转换 之间的解耦
  • 为不同的状态引入不同的对象使得状态转换变得更加明确,而且可以保证不会出现状态不一致的情况,因为转换是原子性的——即要么彻底转换过来,要么不转换;
  • 如果 State 对象没有实例变量,那么各个上下文可以共享同一个 State对象,从而节省对象开销;


2. Memento 备忘录模式

该模式现下已有更成熟更方便的框架工具来进行,所以只学习思想即可,不必拘泥于实现。


2.1 Memento 备忘录模式动机

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

那么如何实现对象状态的良好保存和恢复?但同时又不会因此破坏对象本身的封装性?


2.2 模式定义

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


2.3 实例代码

class Memento {
    string state;
    //.. Memento对于Originator的记录不一定时完整备份,
    //可以根据实际需要进行某些变量的快照即可
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() //caretaker  / ClientApp
{
    Originator orginator;
    //捕获对象状态,存储到备忘录
    Memento mem = orginator.createMomento();
    //...    //改变orginator状态
    //从备忘录中恢复
    orginator.setMomento(memento);
}

2.4 要点总结

  • 备忘录(Memento)存储原发器(Originator)对象的内部状态,在需要时恢复原发器状态
  • Memento模式的核心时信息隐藏,即Originator需要向外界隐藏信息,保持其封装性。但同时有需要将状态保持到外界(Memento);
  • 由于现代语言运行时(如C#,Java等)都具有相当的对象序列化支持,因此往往采用效率较高,又较容易正确实现的序列化方案来实现Memento模式;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值