备忘录模式概念及其解释

备忘录模式是一种行为设计模式, 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。

它在实际开发中用在word、excel等软件的撤销恢复功能、缓存上一页内容、游戏中存档等等

使用场景

  • 当你需要创建对象状态快照来恢复其之前的状态时, 可以使用备忘录模式。

    备忘录模式允许你复制对象中的全部状态 (包括私有成员变量), 并将其独立于对象进行保存。 尽管大部分人因为 “撤销” 这个用例才记得该模式, 但其实它在处理事务 (比如需要在出现错误时回滚一个操作) 的过程中也必不可少。

  • 当直接访问对象的成员变量、 获取器或设置器将导致封装被突破时, 可以使用该模式。

    备忘录让对象自行负责创建其状态的快照。 任何其他对象都不能读取快照, 这有效地保障了数据的安全性。

备忘录模式优缺点

优点

  • 在不破坏对象封装情况的前提下创建对象状态快照
  • 通过让负责人维护原发器状态历史记录来简化原发器代码

缺点

  • 客户端过于频繁地创建备忘录,将消耗大量内存

备忘录模式相关角色

  1. 发起人(Originator):负责创建一个备忘录,记录自身需要保存的状态,具备状态回滚功能

  2. 备忘录(Memento):用于存储Originator的内部状态,可以防止Originator以外的对象访问

  3. 备忘录管理员(Caretaker):负责存储。提供管理员备忘录,无法对备忘录内容进行操作和访问

备忘录模式的实际应用

保存对象状态

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
  // memo角色
class Memo {
constructor(content){
this.content = content;
}
get() {
return this.content;
}
}

// 备忘录管理员
class Caretaker {
constructor(){
this.list = [];
}
add(memo){
this.list.push(memo)
}
get(index){
return this.list[index];
}
}

// 发起人:负责创建一个备忘录,记录自身需要保存的状态,具备状态回滚功能
class Originator {
constructor(){
this.content = null;
}
setContent(content){
this.content = content;
}
getContent(content){
return this.content;
}
saveContentByMemo(){ // 创建备忘录,并记录自身状态
return new Memo(this.content);
}
getContentByMemo(memo){ // 状态回滚
this.content = memo.get();
}
}

let originator = new Originator();
let caretaker = new Caretaker();
originator.setContent('这是demo1');
caretaker.add(originator.saveContentByMemo()); // 存储状态
originator.setContent('这是demo2');
caretaker.add(originator.saveContentByMemo()); // 存储状态
originator.setContent('这是demo3');
console.log(originator.getContent()); // console.log: 这是demo3
originator.getContentByMemo(caretaker.get(1));
console.log(originator.getContent()); // console.log: 这是demo2
originator.getContentByMemo(caretaker.get(0));
console.log(originator.getContent()); // console.log: 这是demo1
</script>

分页时数据缓存

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

// page备忘录
let pageHandle = function() {
// 缓存器
let cache = {};

return function(page, fn) {
if (cache[page]) {

// 1-如果缓存中存在指定页的数据,直接使用
showPage(page, cache[page]); // 页面渲染数据
fn && fn();
} else {
// 2-如果缓存中不存在指定页的数据,则从服务端获取,并将其缓存下来
$.post('xxx', { page: page }, function(res) {
if (res.success) {
showPage(page, res.data); // 页面渲染数据
cache[page] = res.data; // 缓存数据
fn && fn();
} else {
// ajax error
}
});
}
}
};