目录
一.备忘录模式(Memento Pattern)意图
1.角色划分
2.精髓思想
二.最简单的案例:文本编辑器的撤销功能
1.代码
三.为什么要这样设计?
一.备忘录模式(Memento Pattern)意图
在不暴露对象实现细节的前提下,捕获并外部化一个对象的内部状态,以便在后续需要时能够将该对象恢复到原先保存的状态。
1.角色划分
- ①原发器(也叫编辑器)(Originator):文本编辑器本身,能创建备忘录(保存当前内容为一个备忘录版本)和从备忘录恢复(撤销到上一个备忘录版本)
- ②备忘录(Memento):被保存的对象(只允许原发器访问)
- ③负责人(Caretaker):用于存放原发器(也叫编辑器)保存好的备忘录版本(仅存,而不能改)
2.精髓思想
拿我们在txt文本文档写文字时的场景举例:
- 当我们新写了两个字以后,这两个字是停留在原发器(也叫编辑器),因为原发器(也叫编辑器)是用来存放暂时的内容的。
- 当我们的原发器(也叫编辑器)调用了save(保存)方法,该方法会创建一个备忘录对象(即:一个备忘录版本)
- 然后我们需要调用负责人的save(保存)方法,传入上一步那个备忘录对象。就表示“你刚刚在原发器(也叫编辑器)保存的版本,已经被负责人存好了”
- 此时我们可以再写三个字,此时原发器(也叫编辑器)的暂存内容是5个字了(其中2个字的版本已经被保存到负责人,后3个字是新添加的),但此时我们不调用原发器(也叫编辑器)的save(保存)方法。
- 此时我们不想要后面三个字了,怎么办?说白了就是,我还想重新回到那两个字的版本。此时就需要从负责人中,取出之前保存好的备忘录版本;并将该备忘录的内容,重新赋值给原发器(也叫编辑器)的内容(这个内容,在本案例中就是一个String属性,说白了就是输入的文字),此时原发器(也叫编辑器)的暂存内容,就从5个字被覆盖到2个字了,说白了就完成了撤销到上个版本的终极目标。
思考:备忘录模式,保存的具体内容一定是String吗?
答案:不一定。只是本案例举的是txt文本文档的例子,其实可以是任何东西,比如List、Stack等等。无论保存的是啥,总体的思想100%不会变。(说白了保存的具体内容不重要,备忘录模式的重点是如何完成保存、撤销这两个动作,这是终极奥义)
二.最简单的案例:文本编辑器的撤销功能
假设我们有一个简单的文本编辑器,需要支持 "保存状态" 和 "撤销到上一个状态" 的功能。
1.代码
// 1. 备忘录:保存文本状态 class TextMemento { private final String text; // 文本内容 // 构造方法私有,只有原发器能创建 TextMemento(String text) { this.text = text; } // 只允许原发器获取状态 String getText() { return text; } } // 2. 原发器:文本编辑器 class TextEditor { //这是目前暂存的内容 private String text = ""; // 给暂存内容追加文本 public void type(String words) { text += words; } // 保存当前状态到备忘录(根据暂存内容,生成一个备忘录版本,要传给负责人保存起来) public TextMemento save() { return new TextMemento(text); } // 从备忘录恢复状态(根据负责人保存的备忘录版本,覆盖当前编辑器的暂存内容,说白了就是撤销) public void restore(TextMemento memento) { this.text = memento.getText(); } // 显示当前暂存内容 public String getText() { return text; } } // 3. 负责人:管理备忘录(这里简单用一个变量保存最近的状态) class Caretaker { //这是已经保存的备忘录版本 private TextMemento lastMemento; //保存编辑器(即:原发器)传来的备忘录版本 public void saveMemento(TextMemento memento) { lastMemento = memento; } //获取已经保存的备忘录版本(常用于覆盖编辑器内容,这个动作也叫撤销) public TextMemento getLastMemento() { return lastMemento; } } // 测试代码 public class Main { public static void main(String[] args) { TextEditor editor = new TextEditor(); Caretaker caretaker = new Caretaker(); // 在编辑器(原发器)输入一些内容 editor.type("Hello ");//说白了,此时编辑器暂存内容为“Hello ” // 将编辑器(原发器)的暂存内容,保存为一个备忘录版本;然后将该备忘录版本传入负责人中进行保存 caretaker.saveMemento(editor.save()); // 存档1: "Hello " // 再追加点文本 editor.type("World!");//说白了,此时编辑器暂存内容为“Hello World!”,但是没保存 System.out.println("当前文本: " + editor.getText()); // 输出: Hello World! // 撤销到上一次保存的状态(从负责人中,取出保存的备忘录版本,即“Hello ”的那一版);并根据这一版(内容是“Hello ”),覆盖编辑器的暂存内容(说白了就是撤销) editor.restore(caretaker.getLastMemento());//此时暂存内容,会从“Hello World!”,撤销(被覆盖)为“Hello ” System.out.println("撤销后文本: " + editor.getText()); // 输出: Hello } }三.为什么要这样设计?
- 原发器(也叫“编辑器”)(Originator)的内部状态(text 变量)被保护起来,只有它自己能修改
- 备忘录(TextMemento)像个 "密封的盒子",只有原发器能打开
- 负责人(Caretaker)只负责 "保管盒子",不能看里面的内容
这个模式在需要频繁撤销操作的场景非常有用,比如:
- 文本编辑器的撤销 / 重做
- 游戏存档 / 读档
- 数据库事务回滚
以上就是本篇文章的全部内容,喜欢的话可以留个免费的关注呦~~~