备忘录模式
欢迎来到我的 ChatGPT 中转站,极具性价比,为付费不方便的朋友提供便利,有需求的可以添加左侧 QQ 二维码,另外,邀请新用户能获取余额哦!最后说一句,那啥:请自觉遵守《生成式人工智能服务管理暂行办法》。
# 简介
备忘录模式(Memento Pattern)在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保 存的状态。
可以这里理解备忘录模式:现实生活中的备忘录是用来记录某些要去做的事情, 或者是记录已经达成的共同意见的事情,以防忘记了。而在软件层面,备忘录式有着相同的含义,备忘录对象主要用来记录一个对象的某种状态,或者某 些数据,当要做回退时,可以从备忘录对象里获取原来的数据进行恢复操作。
步骤流程为:
- 发起人创建备忘录: 发起人在需要保存当前状态时,创建一个备忘录对象,并将自己的状态保存到备忘录中。
- 发起人传递备忘录给负责人: 发起人将备忘录传递给负责人,负责人负责存储备忘录对象。
- 发起人从备忘录中恢复状态: 当需要恢复到之前的状态时,发起人从负责人那里获取相应的备忘录,并使用备忘录中的状态进行恢复。
备忘录模式中的几个重要角色
发起人(Originator): 发起人是拥有内部状态的对象,它需要在不破坏封装性的前提下捕获自己的内部状态,并且能够根据备忘录恢复到之前的状态。发起人负责创建备忘录和在备忘录中存储自身状态。
备忘录(Memento): 备忘录是用于存储发起人对象状态的对象。备忘录提供了一个窄接口,只能由发起人对象访问。通常,备忘录具有获取和设置发起人状态的方法,但不允许直接修改状态。这样,可以确保发起人的状态不会被外部对象直接访问或修改。
负责人(Caretaker): 负责人是负责存储和管理备忘录的对象。负责人可以持有一个或多个备忘录,并且只有在需要时才能将备忘录传递给发起人。负责人允许发起人恢复到不同的状态,但本身并不了解备忘录的具体内容。
# 代码示例
# 一个备忘录
/**
* 原发器,也就是我们需要保存状态的对象。它可以创建一个备忘录,用于保存其当前状态,也可以使用备忘录来恢复其状态。
*/
@Data
public class Originator {
// 状态,提供set和get方法
private String state;
// 保存,返回一个memento,用来从中恢复
public Memento saveToMemento() {
return new Memento(state);
}
// 恢复
public void restoreFromMemento(Memento memento) {
state = memento.getSavedState();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 备忘录,用于存储原发器的内部状态。备忘录应该防止Originator以外的其他对象访问备忘录。
* 备忘录有两个接口,Caretaker只能看到备忘录的窄接口,它只能将备忘录传递给其他对象。Originator能够看到一个宽接口,允许它访问返回到先前状态所需要的所有数据。
*/
public class Memento {
private final String state;
public Memento(String state) {
this.state = state;
}
//恢复
public String getSavedState() {
return state;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 负责人,负责保存备忘录。它可以保存一个或多个备忘录对象,但不能操作和检查备忘录的内容。
*/
public class Caretaker {
private final List<Memento> mementoList = new ArrayList<>();
public void addMemento(Memento memento) {
mementoList.add(memento);
}
public Memento getMemento(int index) {
return mementoList.get(index);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Client {
public static void main(String[] args) {
// 创建一个原发器
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("状态 1");
System.out.println(originator.getState());
// 保存状态
Memento memento = originator.saveToMemento();
caretaker.addMemento(memento);
// 修改
System.out.println("修改一下吧");
originator.setState("状态 2");
caretaker.addMemento(originator.saveToMemento());
System.out.println(originator.getState());
// 恢复
originator.restoreFromMemento(caretaker.getMemento(0));
System.out.println(originator.getState());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 多个备忘录
需求:游戏角色有攻击力和防御力,在大战 Boss 前保存自身的状态(攻击力和防御力),当大战 Boss 后攻击力和防御力下降,从备忘录对象恢复到大战前的状态。
/**
* 发起者
*/
@Data
public class Originator {
private String name;
private int vit;
private int def;
public Originator(String name, int vit, int def) {
this.name = name;
this.vit = vit;
this.def = def;
System.out.println("当前角色为:" + name + ",攻击力为:" + vit + ",防御力为:" + def);
}
// 保存到备忘录
public Memento saveToMemento() {
return new Memento(vit, def);
}
// 从备忘录恢复
public void restoreFromMemento(Memento memento) {
this.vit = memento.getVit();
this.def = memento.getDef();
System.out.println("当前角色为:" + name + ",攻击力为:" + vit + ",防御力为:" + def);
}
}
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
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
/**
* 备忘录
*/
@Data
public class Memento {
private int vit;
private int def;
public Memento(int vit, int def) {
this.vit = vit;
this.def = def;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
public class Caretaker {
//如果希望保存多个originator对象的不同时间的状态
private final HashMap<String, HashMap<String, Memento>> mementos = new HashMap<>();
/**
* 添加备忘录
* @param originatorId 角色
* @param mementoId 当前时间
* @param memento 当前状态
*/
public void addMemento(String originatorId, String mementoId, Memento memento) {
// 根据角色查询对应的集合,如果存在就返回,不存在就创建一个新的集合
HashMap<String, Memento> originatorMementos = mementos.getOrDefault(originatorId, new HashMap<>());
originatorMementos.put(mementoId, memento);
mementos.put(originatorId, originatorMementos);
}
// 获取备忘录
public Memento getMemento(String originatorId, String mementoId) {
HashMap<String, Memento> originatorMementos = mementos.get(originatorId);
if (originatorMementos == null) {
return null;
}
return originatorMementos.get(mementoId);
}
}
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
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
public class Client {
public static void main(String[] args) {
Caretaker caretaker = new Caretaker();
String name1 = "东东";
String name2 = "西西";
System.out.println("BOSS战开始前");
Originator originator1 = new Originator(name1, 100, 100);
Originator originator2 = new Originator(name2, 50, 50);
//保存状态
caretaker.addMemento(name1, "BOSS战开始前", originator1.saveToMemento());
caretaker.addMemento(name2, "BOSS战开始前", originator2.saveToMemento());
// BOSS战后
System.out.println("BOSS战结束后");
originator1.setVit(50);
originator1.setDef(50);
originator2.setVit(30);
originator2.setDef(30);
caretaker.addMemento(name1, "BOSS战结束后", originator1.saveToMemento());
caretaker.addMemento(name2, "BOSS战结束后", originator2.saveToMemento());
// 休息,回满血
System.out.println("休息,回满血");
originator1.setVit(200);
originator1.setDef(200);
originator2.setVit(100);
originator2.setDef(100);
// 恢复状态--开战之前
System.out.println("恢复到BOSS战前");
Memento memento = caretaker.getMemento(name1, "BOSS战开始前");
originator1.restoreFromMemento(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
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
# 说明
- 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。
- 实现了信息的封装,使得用户不需要关心状态的保存细节。
- 如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存,这个需要注意。
适用的应用场景:
- 后悔药。
- 打游戏时的存档。
- Windows 里的 ctrl + z。
- IE 中的后退。
- 数据库的事务管理。
- 为了节约内存,备忘录模式可以和原型模式配合使用。
上次更新: 2025/08/19, 10:30:51