备忘录(Memento)模式
# 备忘录(Memento)模式
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。对象行为型模式
- 备忘录模式(Memento Pattern)在 不破坏封装性的前提下,捕获 一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态
- 可以这里理解备忘录模式:现实生活中的备忘录是用来记录某些要去做的事情,或者是记录已经达成的共同意见的事情,以防忘记了。而在软件层面,备忘录模式有着相同的含义,备忘录对象主要用来记录一个对象的某种状态,或者某些数据,当要做回退时,可以从备忘录对象里获取原来的数据进行恢复操作

发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
@Data
public class LeiGamer {
// 内部状态,存档时需要存储的信息
Integer coin;
Integer hp;
Integer mp;
Integer level;
GameServer gameServer = new GameServer();
// 保存游戏记录
void saveGameRecord() {
System.out.println("保存当前游戏记录");
//当前游戏信息 保存到备忘录
GameRecord gameRecord = new GameRecord();
gameRecord.setCoin(coin);
gameRecord.setHp(hp);
gameRecord.setMp(mp);
gameRecord.setLevel(level);
gameServer.add(gameRecord);
}
// 从备忘录获取游戏历史存档
LeiGamer getFromMemento(Integer id) {
System.out.println("获取历史存档信息.....");
return gameServer.getRecord(id);
}
// 玩游戏
void playGame() {
System.out.println("coin=" + coin +
", hp=" + hp +
", mp=" + mp +
", level=" + level);
System.out.println("玩游戏中....");
int nextInt = new Random().nextInt();
coin = hp = mp = level = nextInt;
}
// 退出游戏
void exitGame() {
System.out.println("退出并存档");
saveGameRecord();
}
}
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
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
备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
/**
* 游戏记录 也叫备忘录信息
*/
@Data
public class GameRecord {
Integer id;// 代表生成记录的id
Integer coin;
Integer hp;
Integer mp;
Integer level;
// 获取当前备忘录信息
void getCurrent() {
System.out.println("coin=" + coin +
", hp=" + hp +
", mp=" + mp +
", level=" + level);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
/**
* 游戏服务器
* 管理者
*/
public class GameServer {
Map<Integer, GameRecord> records = new HashMap<>();
int i = 1;
void add(GameRecord gameRecord) {
gameRecord.setId(i++);
records.put(gameRecord.id, gameRecord);
}
LeiGamer getRecord(Integer id) {
GameRecord gameRecord = records.get(id);
// 获取到备忘录里的内容 还要进行逆转才能使用
LeiGamer leiGamer = new LeiGamer();
leiGamer.setCoin(gameRecord.getCoin());
leiGamer.setHp(gameRecord.getHp());
leiGamer.setMp(gameRecord.getMp());
leiGamer.setLevel(gameRecord.getLevel());
return leiGamer;
}
}
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
# 应用场景
什么场景用到?
- 游戏存档
- 数据库保存点事务(savepoint)
- session 活化钝化
# 注意事项和细节
- 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态
- 实现了信息的封装,使得用户不需要关心状态的保存细节
- 如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存,这个需要注意
- 适用的应用场景:
- 后悔药。
- 打游戏时的存档。
- Windows 里的 ctri + z。
- IE 中的后退。
- 数据库的事务管理
- 为了节约内存,备忘录模式可以和原型模式配合使用
编辑 (opens new window)
上次更新: 2023/12/13, 06:06:02