备忘录模式用来恢复一个对象的状态到以前的状态。 通俗的说,就是把一个类的属性临时的保存在另一个地方,并提供一个接口可以还原,比较适用的场景是系统升级,代码回滚。
一、类图

备忘录模式包含以下几个角色:
- Originator(原发器):它是一个普通类,可以创建一个备忘录,并存储它的当前内部状态,也可以使用备忘录来恢复其内部状态,一般将需要保存内部状态的类设计为原发器。
- Memento(备忘录):存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录的设计一般可以参考原发器的设计,根据实际需要确定备忘录类中的属性。需要注意的是,除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用,原发器的设计在不同的编程语言中实现机制会有所不同。
- Caretaker(负责人):负责人又称为管理者,它负责保存备忘录,但是不能对备忘录的内容进行操作或检查。在负责人类中可以存储一个或多个备忘录对象,它只负责存储对象,而不能修改对象,也无须知道对象的实现细节。
二、示例
考虑平时玩的通关游戏,每走一步时步数都加一,遇到道具可以快速走几步,或者减几步。用备忘录模式的思想来实现这个逻辑。
游戏类:
class Game {
/**
* 玩家走的步数
*/
private int playerStep;
/**
* 备份游戏
*/
public GameMemento createGameMemento() {
return new GameMemento(playerStep);
}
/**
* 开始玩游戏
*/
public void play() {
playerStep = 0;
}
/**
* 恢复备份
*/
public void restore(GameMemento gameMemento) {
this.playerStep = gameMemento.getPlayerSteps();
}
}
备份
/**
* 备份
*/
class GameMemento {
/**
* 步数
*/
private int playerSteps;
/**
* 备份步数
*/
public GameMemento(int playerSteps) {
this.playerSteps = playerSteps;
}
}
备份信息管理类
/**
* 备份信息管理类
*/
public class Caretaker {
/**
* 备份
*/
private GameMemento gameMemento;
/**
* 恢复备份
*/
public GameMemento retrieveMemento() {
return this.gameMemento;
}
/**
* 保存备份
*/
public void saveMemento(GameMemento gameMemento) {
this.gameMemento = gameMemento;
}
}
测试
public class Player {
public static void main(String[] args) {
Game game = new Game();
System.out.println("游戏开始,捡到滑板,前进10步");
game.setPlayerStep(10);
//备份当前状态
System.out.println("备份当前状态");
GameMemento gameMemento = game.createGameMemento();
Caretaker caretaker = new Caretaker();
caretaker.saveMemento(gameMemento);
System.out.println("备份完成");
game.play();
System.out.println("踩到便便了,当前步数为:" + game.getPlayerStep());
System.out.println("还原到之前一步");
game.restore(caretaker.retrieveMemento());
System.out.println("恢复完成,当前玩家步数是:" + game.getPlayerStep());
}
}
三、备忘录模式的优缺点和适用场景
优点:
当发起人角色中的状态改变时,有可能这是个错误的改变,我们使用备忘录模式就可以把这个错误的改变还原。
备份的状态是保存在发起人角色之外的,这样,发起人角色就不需要对各个备份的状态进行管理。
缺点:
在实际应用中,备忘录模式都是多状态和多备份的,发起人角色的状态需要存储到备忘录对象中,对资源的消耗是比较严重的。