参考文献

备忘录模式

  • 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态.

组件

  • Memento 备忘录
    • 存储 Originator对象的内部状态.状态可以包括任意数量的状态变量.
    • 备忘录必须具有两个接口,一个接口用于负责人(Caretaker).这个接口不能允许任何操作或者访问备忘录存储的内部状态,从而遵循封装原则.另一个接口用于原发器(Originator),允许原发器访问任何必要的状态变量以恢复先前的状态
  • Originator 原发器
    • 创建一个备忘录对象,用于捕获原发器的内部状态.
    • 使用备忘录对象来恢复先前的状态.
  • Caretaker 负责人
    • 负责保持备忘录.
    • 备忘录对于负责人来说是不透明的,而负责人不能对其进行操作.

实现方式

  • 确定担任原发器角色的类取决于你的具体设计需求.如果你的程序只需要一个中心对象作为原发器,则可以创建一个单独的类来扮演这个角色.如果你有多个较小的对象需要保存状态,那么每个对象都可以担任原发器角色.
  • 创建备忘录类时,你需要为每个原发器成员变量声明一个对应的备忘录成员变量.这些备忘录成员变量应该是不可变的,不能包含设置器.
  • 如果你的编程语言支持嵌套类,可以将备忘录嵌套在原发器中.但如果不支持嵌套类,可以从备忘录类中提取一个空接口,然后让其他对象通过接口引用备忘录.在接口中可以添加一些元数据操作,但不能暴露原发器的状态.
  • 在原发器中添加一个创建备忘录的方法,该方法需要通过备忘录构造函数的一个或多个实际参数将自身状态传递给备忘录.返回结果的类型应该是之前提取的接口类型(如果有).创建备忘录的方法需要直接与备忘录类进行交互.
  • 在原发器类中添加一个方法来恢复自身状态,该方法接受备忘录对象作为参数.如果之前提取了接口,参数类型应为接口类型.在这种情况下,你需要将输入对象强制转换为备忘录类型,以便原发器可以完全访问该对象.
  • 负责人(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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import java.util.ArrayList;
import java.util.List;

// 备忘录类
class Memento {
private String state;

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

public String getState() {
return state;
}
}

// 原发器类
class Originator {
private String state;

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

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

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

// 负责人类
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 class MementoPatternExample {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();

// 改变原发器状态并保存备忘录
originator.setState("State 1");
Memento memento1 = originator.createMemento();
caretaker.addMemento(memento1);

// 改变原发器状态并保存备忘录
originator.setState("State 2");
Memento memento2 = originator.createMemento();
caretaker.addMemento(memento2);

// 恢复到第一个备忘录的状态
originator.restoreFromMemento(caretaker.getMemento(0));
System.out.println(originator.getState()); // Output: State 1

// 恢复到第二个备忘录的状态
originator.restoreFromMemento(caretaker.getMemento(1));
System.out.println(originator.getState()); // Output: State 2
}
}

使用场景

  • 当你需要创建对象状态快照来恢复其之前的状态时, 可以使用备忘录模式.
  • 当直接访问对象的成员变量、 获取器或设置器将导致封装被突破时, 可以使用该模式.