:::info 备忘录模式听起来特别高深,其实可能写过几年代码的都不知不觉的用了很多次了。模式的名称其实已经很形象的反映出其作用了:就是为了在某一时刻把当前的状态记录下来,以后再恢复到那时的状态。 :::
定义
在不破坏封闭的前提下捕获一个对象的内部状态,并在该对象之外保存这个状态,从而可以将对象恢复到原先保存的状态
使用场景
当你正在开发一个功能,这个功能需要存档的时候就应该想到它。例如游戏,文档编辑器等等,都需要在你下次重新打开的时候恢复到你关闭它时候的状态。
- 后悔药。
 - 打游戏时的存档。
 - Windows 里的 ctri + z。
 - IE 中的后退。
 - 
UML
角色结构
 Originator:发起人角色
- Memento :备忘录角色
 - 
优点
 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。
- 
缺点
 消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。
业务场景
代码示例
GameOriginator 定义游戏类
public class GameOriginator {private int currentScore;/*** 将需要保存的状态分装在Memento里对外提供*/public GameProgressMemento saveProcess() {return new GameProgressMemento(currentScore);}/*** 通过从外部接收的Memento恢复状态*/public void restoreProcess(GameProgressMemento memento) {currentScore = memento.getScore();}/*** 对内部状态的使用*/public void playGame() {System.out.println("------------------开始游戏------------------");System.out.println("当前分数为:"+ currentScore);System.out.println("杀死一个小怪物得1分");currentScore++;System.out.println(String.format("总分为:%d", currentScore));}public void exitGame(){System.out.println("退出游戏");currentScore=0;System.out.println("-----------------退出游戏-------------------");}}
GameProgressMemento 构建备忘录
这个类最简单,其基本上就是一个POJO。它不包含业务逻辑,只包含状态数据,结构由要保存的状态类决定。例如我们这里只保存一个内部状态,游戏分数。
public class GameProgressMemento {private int score;public GameProgressMemento(int score) {this.score = score;}public int getScore() {return score;}}
GameCareTaker 构建游戏缓存
如果说备忘录模式有一点点技巧的话,也就是这个类了。CareTaker相对于Originator来说是一个外部组件,它帮助Originator保存了状态,相当于Originator将自己某一个时刻的状态保存到了外部。
当我们要保存状态时,使用此类的saveMemento。当我们要恢复状态时,使用此类的getMemento
public class GameCareTaker {private List<GameProgressMemento> memento = new ArrayList<>();public void saveMemento(GameProgressMemento memento) {System.out.println("游戏存档");this.memento.add(memento);}public GameProgressMemento getMemento(int index) {return this.memento.get(index);}}
Client
public class Client {public static void main(String[] args) {GameOriginator originator = new GameOriginator();GameCareTaker careTaker = new GameCareTaker();//玩游戏originator.playGame();//保存进度careTaker.saveMemento(originator.saveProcess());//退出游戏originator.exitGame();//重新打开游戏,恢复进度originator.restoreProcess(careTaker.getMemento(0));originator.playGame();}}
输出
------------------开始游戏------------------当前分数为:0杀死一个小怪物得1分总分为:1游戏存档退出游戏-----------------退出游戏-------------------------------------开始游戏------------------当前分数为:1杀死一个小怪物得1分总分为:2
技术要点总结
- 首先识别出Originator需要保存的状态,然后构建一个备忘录类Memento。
 - Originator需要提供两个方法,一个用于对外提供包含内部状态的备忘录,一个用于使用外部传递进来的备忘录恢复内部状态。
 - CareTaker 负责保存备忘录,并提供访问方法。
 
