一、定义(Definition)
备忘录模式用于在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后恢复到这个状态。
也就是说,它可以让你“撤销/回退”对象的状态,就像文本编辑器中的“Ctrl+Z”。
二、适用场景(When to Use)
- 需要保存对象历史状态,以便将来可以恢复。
- 不希望对象暴露太多内部实现细节。
- 实现撤销/回滚、历史记录、版本控制、状态快照等功能。
三、主要角色(Participants)
角色 | 说明 |
Originator | 发起人对象,拥有内部状态,需要被保存和恢复。 |
Memento | 备忘录对象,存储 Originator 的内部状态(有时是不可变对象)。 |
Caretaker | 管理者,负责存储和管理多个备忘录,但不操作或修改其内容。 |
四、UML 类图
┌────────────────────────────┐
│ Client │
└────────────────────────────┘
│
▼
┌────────────────────────────┐
│ HistoryManager │ ←────────────┐
│ - history: Stack<Memento> │ │
│ + saveState(m: Memento) │ │
│ + undo(): Memento │ │
└────────────────────────────┘ │
│
┌────────────────────────────┐ │
│ Article │──────────────┘
│ - title: String │
│ - content: String │
│ + setContent(c: String) │
│ + show(): void │
│ + saveToMemento(): Memento │
│ + restoreFromMemento(m) │
└────────────────────────────┘
│
▼
┌────────────────────────────┐
│ ArticleMemento │
│ + getTitle(): String │
│ + getContent(): String │
└────────────────────────────┘
五、真实业务场景示例:文档编辑器中的“撤销”功能
背景说明:
假设我们实现一个“文章编辑器”,用户可以修改内容,并支持“撤销”操作。
✅ 1. Originator:文档编辑器类
public class Article {
private String title;
private String content;
public Article(String title, String content) {
this.title = title;
this.content = content;
}
public void setContent(String content) {
this.content = content;
}
public ArticleMemento saveToMemento() {
return new ArticleMemento(title, content);
}
public void restoreFromMemento(ArticleMemento memento) {
this.title = memento.getTitle();
this.content = memento.getContent();
}
public void show() {
System.out.println("标题: " + title);
System.out.println("内容: " + content);
}
}
✅ 2. Memento:文章备忘录类
public class ArticleMemento {
private final String title;
private final String content;
public ArticleMemento(String title, String content) {
this.title = title;
this.content = content;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
}
✅ 3. Caretaker:备忘录管理器(历史记录管理)
import java.util.Stack;
public class HistoryManager {
private Stack<ArticleMemento> history = new Stack<>();
public void saveState(ArticleMemento memento) {
history.push(memento);
}
public ArticleMemento undo() {
if (!history.isEmpty()) {
return history.pop();
}
return null;
}
}
✅ 4. 客户端代码:模拟用户编辑和撤销
public class Client {
public static void main(String[] args) {
Article article = new Article("设计模式", "这是初始内容");
HistoryManager historyManager = new HistoryManager();
// 初始状态保存
historyManager.saveState(article.saveToMemento());
article.show();
System.out.println("\n--- 用户进行第一次修改 ---");
historyManager.saveState(article.saveToMemento()); // 保存旧状态
article.setContent("这是修改后的内容1");
article.show();
System.out.println("\n--- 用户进行第二次修改 ---");
historyManager.saveState(article.saveToMemento()); // 保存旧状态
article.setContent("这是修改后的内容2");
article.show();
System.out.println("\n--- 用户点击撤销 ---");
article.restoreFromMemento(historyManager.undo());
article.show();
System.out.println("\n--- 再次撤销 ---");
article.restoreFromMemento(historyManager.undo());
article.show();
}
}
六、优缺点分析
✅ 优点
- 封装性好:不会暴露对象的内部实现细节。
- 支持撤销/恢复功能:可实现撤销、回滚、历史记录等。
- 与命令模式、状态模式等协同效果好。
❌ 缺点
- 资源开销大:如果备份频繁或对象状态庞大,可能会消耗较多内存。
- 管理复杂性:备忘录的创建和管理逻辑可能复杂,尤其涉及多线程或多个对象时。
七、总结一句话
备忘录模式是一种为需要可回退功能的对象提供“快照”能力的模式,实现状态历史管理而不暴露对象内部细节。