Java 编程之备忘录模式
前言
有时候,我们真希望人生能有“Ctrl+Z”。在日常生活中,我们经常使用“撤销”功能,例如在写 Word、画图、写代码时一不小心操作失误,就希望能回到之前的状态。这种**“状态快照 + 恢复”**机制,在设计模式中就叫做:备忘录模式(Memento Pattern)。
本文将通过一个现实场景——写小说与撤销编辑操作,来贯穿讲解备忘录模式,并用 Java 代码实现一套完整的例子,让你在概念与实践中都收获满满。
一、备忘录模式是什么
定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后将其恢复。
换句话说,它是实现“撤销(Undo)”、“回退(Rollback)”、“恢复(Recover)”的核心设计模式。
二、小说家与“撤销按钮”
想象你是个小说作者,每天都在写小说的草稿。
- 每写一段内容,你都可以“保存一下”(打个草稿快照);
- 写崩了?你就点击“撤销”,恢复之前保存的状态;
- 每一个“保存”其实就是一个备忘录对象(Memento);
- 你就是“发起者(Originator)”;
- 草稿箱(Caretaker)里存着所有的“保存记录”。
三、核心结构类比
角色名 | 类比于现实 | 作用说明 |
---|---|---|
Originator | 小说作者 | 拥有真实内容和状态,可以保存或恢复 |
Memento | 每一段草稿 | 状态快照,保存了当前文本 |
Caretaker | 草稿箱 | 保存多个草稿,但不关心内容细节 |
四、Java 实例
如下以java来实现:小说草稿的撤销与恢复
Memento:草稿快照
// 草稿状态(备忘录)
public class DraftMemento {private final String content;public DraftMemento(String content) {this.content = content;}public String getContent() {return content;}
}
Originator:小说作者
// 发起者,写小说的作者
public class Author {private String content;public void write(String text) {this.content = text;System.out.println("🖊️ 当前写作内容:" + content);}public DraftMemento saveDraft() {System.out.println("📁 保存草稿");return new DraftMemento(content);}public void restoreDraft(DraftMemento memento) {this.content = memento.getContent();System.out.println("↩️ 恢复到草稿:" + content);}public String getContent() {return content;}
}
Caretaker:草稿箱
import java.util.Stack;// 草稿箱,负责保存多个版本
public class DraftCaretaker {private final Stack<DraftMemento> drafts = new Stack<>();public void save(DraftMemento draft) {drafts.push(draft);}public DraftMemento undo() {if (!drafts.isEmpty()) {return drafts.pop();}return null;}public boolean hasHistory() {return !drafts.isEmpty();}
}
测试主类:模拟写作与撤销
public class MementoDemo {public static void main(String[] args) {Author author = new Author();DraftCaretaker caretaker = new DraftCaretaker();author.write("故事的开始:从前有座山");caretaker.save(author.saveDraft());author.write("故事第二章:山里有个庙");caretaker.save(author.saveDraft());author.write("故事第三章:庙里住着老和尚和小和尚");System.out.println("\n⚠️ 写崩了!撤销!");if (caretaker.hasHistory()) {author.restoreDraft(caretaker.undo()); // 撤销到第二章}System.out.println("\n📄 当前内容:" + author.getContent());}
}
输出示例
🖊️ 当前写作内容:故事的开始:从前有座山
📁 保存草稿
🖊️ 当前写作内容:故事第二章:山里有个庙
📁 保存草稿
🖊️ 当前写作内容:故事第三章:庙里住着老和尚和小和尚⚠️ 写崩了!撤销!
↩️ 恢复到草稿:故事第二章:山里有个庙📄 当前内容:故事第二章:山里有个庙
五、UML图
@startuml
title 备忘录模式(Memento Pattern)UML 类图class Author {- content: String+ write(text: String): void+ saveDraft(): DraftMemento+ restoreDraft(memento: DraftMemento): void+ getContent(): String
}class DraftMemento {- content: String+ getContent(): String
}class DraftCaretaker {- drafts: Stack<DraftMemento>+ save(m: DraftMemento): void+ undo(): DraftMemento+ hasHistory(): boolean
}Author --> DraftMemento : 创建备份
DraftCaretaker --> DraftMemento : 保存 & 提取
Author --> DraftCaretaker : 恢复状态
六、适用场景一览
场景 | 描述 |
---|---|
编辑器的撤销重做 | 文本编辑、画图软件 |
游戏存档系统 | 保存玩家状态,失败后恢复 |
数据库事务回滚 | 恢复操作前的状态 |
配置修改回滚 | 系统设置、软件参数 |
七、小结
优点:
- 不破坏封装性,内部状态对外透明
- 实现撤销/恢复简单灵活
- 多状态历史管理方便
注意事项:
- 每次保存都会占用内存,可能引起性能开销
- 状态对象较大时,建议存储增量而非全量
备忘录模式就像我们生活中的“后悔药”,
它帮你把时间打包,瓶中封印,
等你想“回到昨天”,只需轻轻一唤。
八、参考
《23种设计模式概览》