Memento

备忘录

当需要让对象返回之前的状态时(例如,用户请求撤销),就使用备忘录模式。
储存系统关键对象的重要状态。
维护关键对象的封装。

典型情境

游戏保存关卡进度。
Memento Scenario
Memento Sequence

适用性

  • 必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
  • 如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。

结构

Memento Class

Memento - Memento存储Originator对象的内部状态。Originator根据需要决定Memento存储Originator的哪些内部状态。防止Originator以外的其他对象访问Memento。Memento实际上有两个接口,Caretaker智能看到Memento的窄接口——它只能将备忘录传递给其他对象。相反,Originator能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。理想的情况是只允许生成本Memento的那个Originator访问本Memento的内部状态。
Originator - 创建一个Memento,用以记录当前时刻它的内部状态。使用Memento恢复内部状态。
Caretaker - 复杂保存好Memento。不能对Memento的内容进行操作或检查。

协作:
Caretaker向Originator请求一个Memento,保留一段时间后,将其送回给Originator,见交互图。有时管理者不会将Memento返回给Originator,因为Originator可能根本不需要退到先前的状态。
Memento是被动的。只有创建Memento的Originator会对它的状态进行赋值和检索。

示例

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
//---------------------------------------------------
class State
{
public:
State(int d) : m_data(d){}
int m_data;
};
//---------------------------------------------------
class Memento
{
public:
// narrow public interface
virtual ~Memento(){}
protected:
// protected members accessible only to Originator
friend class Originator;
Memento(State s) : m_state(s){}
void set_state(State s)
{

m_state = s;
}
State get_state()
{

return m_state;
}
private:
State m_state;
};
//---------------------------------------------------
class Originator
{
public:
Originator() : m_state(0){}
Memento* create_memento()
{

return new Memento(m_state);
}
void set_memento(Memento* m)
{

if (!m) return;
m_state = m->get_state();
}
void process()
{

m_state.m_data += 10;
}
void print_state()
{

std::cout << "State: " << m_state.m_data << std::endl;
}
private:
State m_state; // internal data structure
};
//---------------------------------------------------
class Caretaker
{
public:
Caretaker(): m_originator(new Originator()){}
void test()
{

if(!m_originator) return;
m_originator->process();
std::cout << "Save: "<< std::endl;
m_originator->print_state();
// 保存当前状态
Memento* saved = m_originator->create_memento();
m_originator->process();
m_originator->process();
std::cout << "Later: "<< std::endl;
m_originator->print_state();
// 恢复之前状态
m_originator->set_memento(saved);
std::cout << "Restore: "<< std::endl;
m_originator->print_state();
}
protected:
Originator* m_originator;
};
//---------------------------------------------------
int main()
{

Caretaker c;
c.test();
system("Pause");
}

优点

  • 将被储存的状态放在外面,不要和关键对象混在一起,这可以帮助维护内聚。
  • 保持关键对象的数据封装。
  • 提供了容易实现的恢复能力。

用途和缺点

  • 备忘录用于储存状态。
  • 使用备忘录的缺点:储存和恢复状态的过程可能相当耗时。

相关模式

  • Command: 命令可使用备忘录来为可撤销的操作维护状态。
  • Iterator: 备忘录可用于迭代。

[1] 设计模式:可复用面向对象软件的基础
[2] Head First设计模式