# 备忘录模式
1.简介
备忘录模式是一种行为设计模式,允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。
简单的来说就是在某一时刻把当前状态记录下来,以后可以选择性的再恢复到某次保存的状态。
例如游戏中的存档、编辑器中的 crtl+z
、浏览器中的后退、数据库的事务管理等等。
2.UML图
- **原发器(Originator):**类可以生成自身状态的快找,也可以在需要时通过快照恢复自身状态。
- **备忘录(Memento):**是原发器状态快照的值对象。通常做法是将备忘录设为不可变得,并通过构造函数一次性传递数据。
- **负责人(Caretaker):**仅知道
何时、为何
捕捉原发器的状态,以及何时恢复状态。 负责人通过保存备忘录栈来记录原发器的历史状态,当原发器需要回溯历史状态时,负责人将从栈中获取最顶部的备忘录,并将其传给原发器的恢复方法。 - 在该实现方法中,备忘录类将被嵌套在原发器中。这样原发器就可以访问备忘录的成员变量和方法,即使这些方法被声明为私有。另一方面,负责人对于备忘录的成员变量和方法的访问权限非常有限;它们只能在栈中保存备忘录,而不能修改其状态。
3.代码示例
我们来写一个游戏存档的例子。
首先定义Originator(游戏类):
我们需要保存和读取游戏进度,它内部提供了两个方法,一个是对外提供备忘录(封装了要恢复的内部状态)。另一个是从外接受备忘录,用来恢复内部状态。
java
package com.gs.designmodel.memento;
/**
* @author: Gaos
* @Date: 2023-08-22 18:35
**/
public class GameOriginator {
private int currentScore;
/**
* 将需要保存的状态封装在Memento里对外提供
* @return
*/
public GameProgressMemento saveProcess() {
return new GameProgressMemento(currentScore);
}
/**
* 通过从外部接收的Memento恢复状态
* @param memento
*/
public void restoreProcess(GameProgressMemento memento) {
currentScore = memento.getScore();
}
public void playGame() {
System.out.println("Game Begin---");
System.out.println("当前分数为: " + currentScore);
System.out.println("击杀小兵得一分");
currentScore++;
System.out.println("总分为: " + currentScore);
}
public void exitGame() {
System.out.println("退出游戏");
currentScore = 0;
System.out.println("Game End-----");
}
}
构建Memento(备忘录):
就只是一个简单的实体类,不包含业务逻辑只包含数据状态,结构由要保存的状态类决定,我们这里只保存一个游戏分数。
java
package com.gs.designmodel.memento;
/**
* @author: Gaos
* @Date: 2023-08-22 18:38
**/
public class GameProgressMemento {
private int score;
public GameProgressMemento(int score) {
this.score = score;
}
public int getScore() {
return score;
}
}
构建CareTaker(负责人):
CareTaker
相对于 Originator
来说是一个外部组件,它帮助 Originator
保存了状态。
java
package com.gs.designmodel.memento;
import java.util.ArrayList;
import java.util.List;
/**
* @author: Gaos
* @Date: 2023-08-22 18:38
**/
public class GameCareTaker {
private List<GameProgressMemento> mementos = new ArrayList<>();
/**
* 保存状态
* @param memento
*/
public void saveMemento(GameProgressMemento memento) {
this.mementos.add(memento);
}
/**
* 恢复状态
* @param index
* @return
*/
public GameProgressMemento getMemento(int index) {
return this.mementos.get(index);
}
}
测试类:
java
package com.gs.designmodel.memento;
/**
* @author: Gaos
* @Date: 2023-08-22 18:46
**/
public class Test {
public static void main(String[] args) {
GameOriginator originator = new GameOriginator();
GameCareTaker careTaker = new GameCareTaker();
// 客户端需要维护一个指针和备忘录的次序相对应
int index = 0;
// 玩游戏
originator.playGame();
// 保存进度
careTaker.saveMemento(originator.saveProcess());
// 退出游戏
originator.exitGame();
// 重新打开游戏恢复进度
originator.restoreProcess(careTaker.getMemento(index));
originator.playGame();
}
}
结果:
sql
Game Begin---
当前分数为: 0
击杀小兵得一分
总分为: 1
退出游戏
Game End-----
Game Begin---
当前分数为: 1
击杀小兵得一分
总分为: 2
4.总结
当你需要创建对象状态快照来恢复其之前的状态时,你可以使用备忘录模式。当对象的安全性被突破时你可以使用备忘录模式。(备忘录让对象自行负责创建其状态的快找,其他任何对象都不能读取快照,这保障了数据的安全性)
你可以使用 命令模式和备忘录模式来实现撤销,命令对目标对象执行各种不同的操作,备忘录用来保存一条命令执行前盖对象的状态。但是如果客户端太过于频繁的创建备忘录,程序将消耗大量内存,同时 负责人(CareTaker)必须根据原发器的生命周期,这样才能销毁弃用的备忘录。
参考文章:
希望这篇文章对大家有所帮助,您的赞和收藏是对我最大的支持和认可!