Earth Guardian

You are not LATE!You are not EARLY!

0%

设计模式--行为型:备忘录模式

备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。后期可以直接将该对象恢复到原先保存的状态

备忘录模式

备忘录模式 Memento[məˈmentoʊ] Pattern:常用于存档,编辑回退等场景,主要是保存某个对象当前的状态。

类图结构

0066-Memento-uml-classdiag.png

结构解析

  • Originator[əˈrɪdʒəˌnetɚ]
    发起者,复杂类有多个属性。负责创建一个备忘录,用于记录当前内部状态,并可以使用备忘录恢复状态。Originator 来决定需要备忘录存储哪些状态或属性。
  • Memento
    备忘录,负责存储 Originator 指定的内部状态。只能通过 Originator 创建修改状态,其他类仅仅可以获取状态。
  • CareTaker
    管理类,负责存储管理保存好的备忘录列表,但是不能修改备忘录中保存的状态。

Originator 负责指定 Memento 保存自己的哪些内部状态,CareTaker 维护一个列表保存 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
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
// 1. Memento
public class Memento {
private String state;

public Memento(String state) {
this.state = state;
}

public String getState() {
return state;
}
}

// 2. Originator
public class Originator {
private String state;
private String otherInfo;

public Memento createMemento(){
return new Memento(state);
}

public void restore(Memento memento){
state = memento.getState();
}

public String getState() {
return state;
}

public void setState(String state) {
this.state = state;
}

public String getOtherInfo() {
return otherInfo;
}

public void setOtherInfo(String otherInfo) {
this.otherInfo = otherInfo;
}
}

// 3. CareTaker
public class CareTaker {
private List<Memento> mementos = new ArrayList<>();

public void addMemento(Memento memento){
mementos.add(memento);
}

public Memento getMemento(int index){
return mementos.get(index);
}

public void removeMemento(Memento memento){
mementos.remove(memento);
}

public int size(){
return mementos.size();
}
}

// 4. Test
public class TestMemento {
public static void main(String[] args) {
Originator originator = new Originator();
originator.setState("first state");
originator.setOtherInfo("other info");

CareTaker careTaker = new CareTaker();
careTaker.addMemento(originator.createMemento());

originator.setState("second state");
originator.setState("third state");
careTaker.addMemento(originator.createMemento());
System.out.println("Originator current state: "
+ originator.getState());
if (careTaker.size() > 0){
originator.restore(careTaker.getMemento(0));
System.out.println("restore, Originator current state: "
+ originator.getState());
}
}
}

// 5. Result
Originator current state: third state
restore, Originator current state: first state

总结

按照 GOF 定义的备忘录模式,需要备忘录只能对发起方 Originator 可见,其他类无法获取其状态,这样根据备忘录的可见性,可以做如下分类:

  • 白箱模式
    备忘录完全可见,暴露给其他类,这种是最常见的备忘录模式,上面的代码示例即为白箱模式。
  • 黑箱模式
    备忘录抽象一个空接口出来,而备忘录则以内部类的形式在 Originator 中实现对应功能,这样外部类在访问的时候,只能拿到空接口。
    备忘录中的宽窄接口:接口类中提供比较完备的操作状态的方法,我们称它为宽接口;而只是一个标示或者空接口,我们称它为窄接口。备忘录角色在实现这两种接口类时,可以控制对于“备忘发起角色”采用宽接口进行访问,而对于其他的角色或者对象则采用窄接口进行访问。黑箱模式正是采用了这种方式来实现的。

参考文档

  • 大话设计模式
  • Android 源码设计模式解析与实战
  • 备忘录模式