👉文章示例代码👈
定义
在不破坏封装性的前提下,捕获一个对象的内部状态,并且在该对象之外保存这个状态,从而可以在将来合适的时候把这个对象还原到之前保存的状态。
备忘录模式也叫快照模式。
三个角色
备忘录模式主要的角色有以下三个:
- 发起人Originator:负责创建一个备忘录,记录当前时刻发起人的内部状态,同时提供恢复备忘录数据的能力。
- 备忘录Memento:负责存储发起人对象的内部状态。
- 管理者Caretaker:对备忘录进行管理,提供保存与获取备忘录的功能,但是不能对备忘录的内容进行操作或者检查。
场景示例
我们在使用 IntelliJ IDEA
进行开发的时候,IntelliJ IDEA
会将所有的更改进行自动保存。而且在我们开发的任何阶段我们都可以对不必要的更改进行还原操作,让任何文件或者目录都可以恢复到更改之前的任何状态。
笔者这里就 IntelliJ IDEA
的保存和还原更改为例来进行简单的示例说明。
创建发起人
在该示例当中,我们是对代码文件进行备份,所以其可以作为是一个发起人角色。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
|
public class CodeFile {
private String className;
private String content;
private String code;
public CodeFile(String className, String content, String code) { this.className = className; this.content = content; this.code = code; }
public CodeFileMemento saveToMemento() { System.out.println("创建了一个新的备份, 备份编号: " + this.code); return new CodeFileMemento(this.className, this.content, this.code); }
public void undoFromMemento(CodeFileMemento codeFileMemento) { System.out.println("撤销代码文件至原先备份, 内容为: " + codeFileMemento); this.className = codeFileMemento.getClassName(); this.content = codeFileMemento.getContent(); this.code = codeFileMemento.getCode(); }
@Override public String toString() { return "CodeFile{" + "className='" + className + '\'' + ", content='" + content + '\'' + ", code='" + code + '\'' + '}'; } }
|
创建备忘录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
public class CodeFileMemento {
private String className;
private String content;
private String code;
public CodeFileMemento(String className, String content, String code) { this.className = className; this.content = content; this.code = code; }
public String getClassName() { return className; }
public String getContent() { return content; }
public String getCode() { return code; }
@Override public String toString() { return "CodeFileMemento{" + "className='" + className + '\'' + ", content='" + content + '\'' + ", code='" + code + '\'' + '}'; } }
|
创建管理者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public class CodeFileMementoManager {
private final Stack<CodeFileMemento> CODE_FILE_MEMENTO_STACK = new Stack<CodeFileMemento>();
public CodeFileMemento getCodeFileMemento() { return CODE_FILE_MEMENTO_STACK.pop(); }
public void addCodeFileMemento(CodeFileMemento codeFileMemento) { CODE_FILE_MEMENTO_STACK.push(codeFileMemento); } }
|
测试类及输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
public class Test {
public static void main(String[] args) { CodeFileMementoManager codeFileMementoManager = new CodeFileMementoManager();
CodeFile codeFile = new CodeFile("Test", "public class Test {}", "bak-0001"); CodeFileMemento codeFileMemento = codeFile.saveToMemento(); codeFileMementoManager.addCodeFileMemento(codeFileMemento);
codeFile.setContent("public class Test {public static void main(String[] args) {}}"); codeFile.setCode("bak-0002");
System.out.println("当前文件内容: " + codeFile);
CodeFileMemento rollbackMemento = codeFileMementoManager.getCodeFileMemento(); codeFile.undoFromMemento(rollbackMemento); System.out.println("执行撤销操作后, 当前文件内容: " + codeFile); } }
|
测试类的输出结果如下:
创建了一个新的备份, 备份编号: bak-0001
当前文件内容: CodeFile{className=’Test’, content=’public class Test {public static void main(String[] args) {}}’, code=’bak-0002’}
撤销代码文件至原先备份, 内容为: CodeFileMemento{className=’Test’, content=’public class Test {}’, code=’bak-0001’}
执行撤销操作后, 当前文件内容: CodeFile{className=’Test’, content=’public class Test {}’, code=’bak-0001’}
类结构图
以上示例类的结构图如下所示

从类图中我们可以看到,我们的 CodeFileMemento
(备忘录角色)只能由我们的 CodeFile
(发起人角色)来创建,而 CodeFileMemento
(备忘录角色)和 CodeFileMementoManager
(管理者角色)之间是一个聚合关系。
总结
适用场景
- 需要保存与恢复数据的相关业务场景。
- 需要提供一个可以回滚操作的场景,即可以恢复到之前保存的状态。
优点
- 为用户提供了一种可以恢复状态的机制。
- 保持关键对象的数据封装。
缺点
对象需要保存的内部状态信息过多或者操作频繁时,会占用比较大的内存资源。
参考