备忘录模式

  • 定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原来保存的状态
  • 基于嵌套类实现
    备忘录模式
  • 基于中间接口实现
    备忘录模式
  • 更严格实现
    备忘录模式
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// 发起者:负责创建一个备忘录
class Originator {
/**
* For the sake of simplicity, the originator's state is stored inside a
* single variable.
*/
private state: string;

constructor(state: string) {
this.state = state;
console.log(`Originator: My initial state is: ${state}`);
}

/**
* The Originator's business logic may affect its internal state. Therefore,
* the client should backup the state before launching methods of the
* business logic via the save() method.
*/
public doSomething(): void {
console.log('Originator: I\'m doing something important.');
this.state = this.generateRandomString(30);
console.log(`Originator: and my state has changed to: ${this.state}`);
}

private generateRandomString(length: number = 10): string {
const charSet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

return Array
.apply(null, { length })
.map(() => charSet.charAt(Math.floor(Math.random() * charSet.length)))
.join('');
}

/**
* Saves the current state inside a memento.
*/
public save(): Memento {
return new ConcreteMemento(this.state);
}

/**
* Restores the Originator's state from a memento object.
*/
public restore(memento: Memento): void {
this.state = memento.getState();
console.log(`Originator: My state has changed to: ${this.state}`);
}
}
// 备忘录定义
interface Memento {
getState(): string;

getName(): string;

getDate(): string;
}
// 备忘录实现
class ConcreteMemento implements Memento {
private state: string;

private date: string;

constructor(state: string) {
this.state = state;
this.date = new Date().toISOString().slice(0, 19).replace('T', ' ');
}

/**
* The Originator uses this method when restoring its state.
*/
public getState(): string {
return this.state;
}

/**
* The rest of the methods are used by the Caretaker to display metadata.
*/
public getName(): string {
return `${this.date} / (${this.state.substr(0, 9)}...)`;
}

public getDate(): string {
return this.date;
}
}
// 管理者
class Caretaker {
private mementos: Memento[] = [];

private originator: Originator;

constructor(originator: Originator) {
this.originator = originator;
}

public backup(): void {
console.log('\nCaretaker: Saving Originator\'s state...');
this.mementos.push(this.originator.save());
}

public undo(): void {
if (!this.mementos.length) {
return;
}
const memento = this.mementos.pop();

console.log(`Caretaker: Restoring state to: ${memento.getName()}`);
this.originator.restore(memento);
}

public showHistory(): void {
console.log('Caretaker: Here\'s the list of mementos:');
for (const memento of this.mementos) {
console.log(memento.getName());
}
}
}
// 使用
const originator = new Originator('Super-duper-super-puper-super.');
const caretaker = new Caretaker(originator);

caretaker.backup();
originator.doSomething();

caretaker.backup();
originator.doSomething();

caretaker.backup();
originator.doSomething();

console.log('');
caretaker.showHistory();

console.log('\nClient: Now, let\'s rollback!\n');
caretaker.undo();

console.log('\nClient: Once more!\n');
caretaker.undo();

优缺点

  • 优点
    • 可以创建快照
    • 可以简化代码
  • 缺点
    • 如果保存频繁,将消耗大量内存
    • 动态语言不能保证备忘录中的状态不被修改