(learn&think)

不浮躁,不自傲,学习,思考,总结

浅谈设计模式二十二: 备忘录模式(Memento)

| Comments

1 实例

一个对象的状态必须被存储下来以便它之后能恢复到那个状态,并且一个直接获取状态的接口将暴露实现的细节并破坏对象的封装。 那么如何不用直接获取状态的情况下,实现状态的存储和恢复呢?

2 备忘录模式(Memento)

2.1 目的

不破坏封装的前提下,采集和外部化对象的内部状态,以便这个对象能被恢复到这状态之后。

2.2 实现

只有一个状态标识需要保存和恢复的简单发起类演示备忘录模式。代码实例在这里

2.2.1 需要保存和恢复状态的发起类

  1. CreateMemento :创建一个包含它当前内部状态快照的备忘录类。
  2. SetMemento :使用备忘录类恢复它的内部状态。
template<typename T>
class Originator {
 public:
  virtual ~Originator() {}
  Memento<T>* CreateMemento() {
    Memento<T> *m = new Memento<T>();
    m->set_state(state_);
    return m;
  }
  void SetMemento(Memento<T> *m) {
    state_ = m->state();
  }
  void set_state(const T &state) {state_ = state;}
  void ShowState() const {
    cout << state_ << endl;
  }
 private:
  T state_;
};

2.2.2 备忘录类

保存和返回状态。

template<typename T>
class Memento {
 public:
  virtual ~Memento() {}
  T state() const {return state_;}
  void set_state(T state) {state_ = state;}
 private:
  T state_;
};

2.2.3 管理者

负责备忘录的保护。用 vector 存储备忘录类以便发起者恢复状态。

class Caretaker {
 public:
  virtual ~Caretaker() {}
  void SaveState(Originator<T> *orig) {
    memento_array_.push_back(orig->CreateMemento());
  }
  void RestoreState(Originator<T> *orig, int state_number) {
    orig->SetMemento(memento_array_[state_number]);
  }
 private:
  vector<Memento<T> *> memento_array_;
};

3 总结

3.1 备忘录模式(Memento)结构

3.2 组成

  • 备忘录类(Memento)
    1. 存储发起者(Originator)对象的内部状态。根据它的发起者的判定,备忘录存储尽量多或尽量少的发起者的内部状态。
    2. 防止发起者以外的对象访问。备忘录类实际有两个接口。管理者(Caretaker)拥有备忘录的窄接口——它只能把备忘录类传递给其他对象。发起者(Originator)相反拥有宽接口,让它访问所有必须的数据来自我恢复到之前状态。理想情况下,只有创建备忘录类的那个发起者才允许访问备忘录类的内部状态。
  • 发起者(Originator)
    1. 创建一个包含它当前内部状态快照的备忘录类。
    2. 使用备忘录类恢复它的内部状态。
  • 管理者(Caretaker)
    1. 负责备忘录的保护。
    2. 从不操作或检查备忘录类的内容。

3.3 应用场景

  • 一个对象的(或部分)状态快照必须被存储下来以便它之后能恢复到那个状态,并且
  • 一个直接获取状态的接口将暴露实现的细节并且破坏对象的封装。

3.4 缺点

  • 使用备忘录模式可能会开销很大。备忘录模式会导致很大的开销如果发起类必须在备忘录类你拷贝很大量的信息来恢复或如果客户过多的创建和返回备忘录给创建者。除非封装和恢复发起类状态的开销比较小,否则这个模式可能并不适合。
  • 定义窄和宽接口。在一些编程语言里确保只有发起类能访问备忘录类的状态可能比较困难。
  • 管理备忘录类的隐藏开销。一个管理者(caretaker)负责删除它管理的备忘录类。然而,这个管理者不清楚到底有多少的状态存储在备忘录里。因此一个轻量级管理者反而会引起大的存储开销当它存储备忘录时。

Comments