模式动机(Memento Pattern):我们在编辑文档时,经常需要将刚删除的内容恢复过来,这时最常用的就是撤销命令(Ctrl + Z)了,但是这种功能是如何实现的呢?
可以猜想,其内部必然维护一个保存已删除内容的机制,这就是备忘录模式的用途了。
其实在软件开发过程中,为了不同模块之间的交互,很多情况下需要记录一个对象内部状态的信息,以便可以进行恢复操作。比如,数据库的“回滚”操作,浏览器的“恢复上 一次”操作等。
备忘录模式的一般定义为:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样在某个时刻就可以将该对象恢复到原来的状态。
模式结构图:
模式代码:
bt_备忘录模式.h:
1 #ifndef MP_H 2 #define MP_H 3 #include <iostream> 4 using namespace std; 5 6 /* 7 状态结构体 8 */ 9 typedef struct State 10 { 11 public: 12 State(int h = 0, int w = 0) : height(h), width(w){ }; 13 void SetState(int h, int w) 14 { 15 height = h; 16 width = w; 17 } 18 19 int height; 20 int width; 21 }State; 22 23 /* 24 备忘录 25 */ 26 class Memento 27 { 28 public: 29 Memento(State* s) 30 { 31 state = new State(s->height, s->width); // new出新状态执行深复制 32 } 33 ~Memento() 34 { 35 delete state; 36 } 37 State* GetState() const 38 { 39 return state; 40 } 41 void SetState(State* state) 42 { 43 this->state = state; 44 } 45 private: 46 friend class Originator; 47 State* state; 48 49 }; 50 51 /* 52 原发器 53 */ 54 class Originator 55 { 56 public: 57 Originator(State* s) : state(s){ } 58 void SetMemento(const Memento* m) 59 { 60 this->state= m->GetState(); 61 } 62 Memento* CreateMemento() 63 { 64 return new Memento(state); // 此处若以指针类型的state传入构建新的备忘录,必须执行深复制, 65 // 否则后期改变state时,备忘录中的state状态将会跟着改变; 66 // 此外就是将state改为值传递形式,这样备忘录中保存的副本不受影响 67 } 68 // 显示当前状态 69 void Show() 70 { 71 cout << "当前状态为:"; 72 cout << "height = " << state->height << ", " << "width = " << state->width << endl; 73 } 74 75 private: 76 State* state; 77 }; 78 79 /* 80 管理者:负责保存、传递当前备忘录 81 */ 82 class Caretaker 83 { 84 public: 85 void SetMemento(Memento* m) 86 { 87 this->memento= m; 88 } 89 Memento* GetMemento() 90 { 91 return memento; 92 } 93 private: 94 Memento* memento; 95 }; 96 97 #endif // MP_H
测试用例.cpp:
1 #include "bt_备忘录模式.h" 2 3 int main() 4 { 5 cout << "***** 备忘录模式测试 *****" << endl; 6 State* s = new State(100, 50); 7 Originator* original = new Originator(s); 8 Caretaker* ct = new Caretaker(); 9 ct->SetMemento(original->CreateMemento()); // 用备忘录保存当前状态 10 original->Show(); 11 12 cout << endl; 13 s->SetState(200, 100); // 改变状态 14 original->Show(); 15 16 cout << endl; 17 original->SetMemento(ct->GetMemento()); // 恢复状态 18 original->Show(); 19 20 delete ct; 21 delete original; 22 delete s; 23 24 return 0; 25 }
模式分析:
:: 备忘录用来存储原发器在前一时刻的内部状态,当需要设置恢复点时,管理者请求原发器创建一个备忘录,并记录原发器的当前状态。
:: 备忘录的状态只有创建它的原发器可以修改,因此将原发器类设为备忘录的友元类,用于访问备忘录的私有数据。
:: 管理者的作用是保存备忘录,必要时向原发器传递备忘录以恢复原发器的前一个状态。
:: 备忘录模式实现了状态恢复功能,其将原发器的内部状态进行保存,而且只允许创建它的原发器进行修改,封装性较好,同时若在管理者中采用栈来保存多个备忘录就可以实现 多次撤销操作。
:: 该模式与命令模式结合起来可以有效地实现撤销和重做命令,管理者可以利用STL容器来保存多个备忘录。