这是我参与2022首次更文挑战的第22天,活动详情查看:2022首次更文挑战
备忘录模式
备忘录模式的概念
备忘录(Memento Pattern)模式也被称为快照模式(Snapshot Pattern),备忘录模式主要是指在不破坏封装性的前提下,捕捉一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。备忘录模式在类的创建过程中属于行为型模式。
在软件系统中,备忘录模式可以保存我们提交的一次快照请求后所产生的相关快照,可以通过存储系统各个历史状态的快照,使得我们可以在任一时刻将系统回滚到某一个历史状态。
备忘录模式本质:从发起人实体类(Originator)隔离存储功能,降低实体类的职责。同时由于存储信息(Memento)独立,且存储信息的实体交由管理类(Caretaker)管理,则可以通过为管理类扩展额外的功能对存储信息进行扩展操作(比如增加历史快照功能···)。
备忘录模式的应用场景
备忘录模式在现实中使用的很多,特别是代码中使用
-
Git、SVN的代码回滚等操作
-
需要保存与恢复数据的场景,如玩游戏时的中间结果的存档功能。
-
需要提供一个可回滚操作的场景,如 Word、记事本、Photoshop,Eclipse 等软件在编辑时按 Ctrl+Z 组合键,还有数据库中事务操作。
备忘录模式的通用写法
通常情况下备忘录模式一般具有三种角色
-
发起人(Originator)角色:负责创建一个备忘录,记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
-
备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人,并且可以防止除了发起人以外的人访问。
-
备忘录管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
通过玩游戏存档的例子来充分展示备忘录模式
- Gamer(游戏发起人角色)
public class Gamer {
Integer coin;
Integer hp;
Integer mp;
Integer level;
//以上内部状态,需要保存
GameServer gameServer = new GameServer();
void saveGameRecord() throws InvocationTargetException, IllegalAccessException {
System.out.println("正在保存当前记录......");
GameRecord gameRecord = new GameRecord();
BeanUtils.copyProperties(gameRecord, this);
gameServer.add(gameRecord);
}
Gamer getFromMemento(Integer id) throws Exception {
System.out.println("获取历史存档信息。。。。");
Gamer gameRecord = gameServer.getGameRecord(id);
return gameRecord;
}
}
- GameRecord(备忘录角色)
public class GameRecord {
Integer id;
Integer coin;
Integer hp;
Integer mp;
Integer level;
/**
* 获取备忘录信息
*/
void getCurrent() {
System.out.println("coin: " + coin + "; \t" + "hp: " + hp + "; \t" + "mp:" + mp);
}
}
- GameServer(备忘录管理角色)
public class GameServer {
/**
* 管理备忘录信息
*/
Map<Integer, GameRecord> records = new HashMap<>();
Integer i = 1;
void add(GameRecord gameRecord) {
gameRecord.setId(i++);
records.put(gameRecord.id, gameRecord);
}
Gamer getGameRecord(Integer id) throws Exception {
GameRecord gameRecord = records.get(id);
//获取到备忘录里面内容以后还要逆转
Gamer gamer = new Gamer();
BeanUtils.copyProperties(gamer, gameRecord);
return gamer;
}
}
- UML结构图
通过上面的代码和UML结构图可以看到,发起人角色(Gamer)里面存储了很多需要记录和保存的属性,比如coin、level等信息,同时创建了一个备忘录管理者对象(GameServe),通过saveGameRecord方法开保存当前时刻的所有信息,然后通过getFromMemento方法可以获取到之前保存的游戏信息存档。而备忘录角色存储的就是需要存档的游戏信息。备忘录管理者(GameServer)其实就是用来保存每一次发起备忘录的所有记录,通常情况下是以map集合保存的。
备忘录模式的优缺点
优点
-
提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
-
实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
-
简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。
缺点
- 资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。\