【转】设计模式学习笔记(18)-备忘录
备忘录模式(Memento),顾名思义,为一个对象提供一个记录它状态的地方,这样当这个对象想要返回到它以前的某个状态时,拿出备忘录,照上面记录的信息完全恢复成原来的样子。这其实相当于为这个对象建立了一个快照,这样当一系列操作完成之后便可以根据该快照精确地回退到对象建立快照的状态。这简直和命令模式是绝配啊,命令模式可以支持撤销操作,备忘录可以精准地记录对象内部状态而不破环封装性。
备忘录模式是怎样进行操作的呢?其实和玩游戏中常用的S/L(Save/Load)大法差不多,在进行有风险、可能具有破坏性操作之前先建立一个备忘录,然后放手去做该做的操作,一旦发现出错了,或是用户取消了操作,赶紧取出备忘录,恢复状态,好像什么都没有发生一样。这是不是很像数据库中事务的概念呢?
其中Memento是备忘录,Originator是应该需要保存的类,Caretaker是维护Memento的类,应为可能有不止一个Memento。
我们来实现一个十分简单的备忘录模式,假设有一个矩形,我们需要在它进行移动之后回到原来的位置。我们分别建立一下几个类:
|
1
2
3
4
5
6
|
class Position {public: int x; int y;}; |
Position反映矩形的位置
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Memento{private: Position _postion;public: Memento(Position& pos) { _postion.x = pos.x; _postion.y = pos.y; } Position& GetPosition() { return _postion; } void SetPosition(Position& pos) { _postion.x = pos.x; _postion.y = pos.y; }}; |
这就是Memento啦,代码很简单,不用多说
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
class Rect {private: Position _postion;public: Memento* createMemento() { return new Memento(_postion); } void SetMemento(Memento& memento){ _postion = memento.GetPosition(); } Rect(int x, int y) { _postion.x = x; _postion.y = y; } void Say() { cout << "Rect At:" << _postion.x << "," << _postion.y << endl; } void MoveX(int x) { _postion.x += x; } void MoveY(int y) { _postion.y += y; }}; |
这是需要记录的类,Rect,拥有Move方法可以移动
|
1
2
3
4
5
6
7
8
|
Rect rect(1, 2);rect.Say();Memento* mem = rect.createMemento();rect.MoveX(-10);rect.MoveY(12);rect.Say();rect.SetMemento(*mem);rect.Say(); |
这是主方法,先初始化一个Rect对象,然后创建一个备忘录,移动一下,再恢复过来。所以最终结果为:
|
1
2
3
|
Rect At:1,2Rect At:-9,14Rect At:1,2 |
这样就将对象完全恢复到原来的状态了。
得,备忘录真的没什么好说的。我们同时也应该看到使用备忘录往往意味着开销较大,就像备份会消耗磁盘空间一样,所以有了一种称之为增量备份的技术,使用增量式可以有效降低存储开销,代之以较大计算量。
最后来看看备忘录模式的适用性:
- 必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态
- 如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性
备忘录模式基本上就这些,有利有弊,一般是与Command模式结合起来使用的。
转自: http://lecoding.com/articles/250.html
posted on 2013-03-05 16:30 TheKingOfKingFish 阅读(107) 评论(0) 收藏 举报

浙公网安备 33010602011771号