概念
在不破坏对象封装性的前提下,捕获一个对象的内部状态,并在将来需要的时候能够恢复这个状态
应用场景
遇到需要“恢复历史状态”的场景。如果每次都让对象自己暴露内部属性,自己去记录变化,不仅会破坏封装性,还容易导致逻辑混乱。使用备忘录模式后,对象可以把自己当前的状态保存到一个独立的备忘录对象里,既能保证对象的封装性,又能让我们在需要的时候,简单、安全地恢复到之前的状态
基本结构

1)发起人(Originator):需要保存状态的对象,负责创建和恢复备忘录
2)备忘录(Memento):存储发起人的内部状态,是一个纯数据对象
3)管理者(Caretaker):负责保存备忘录对象,但不直接操作备忘录的内容
代码实现
以“文本备忘录”为例
备忘录
纯数据类,作为“发起人”的备份
只提供读取的功能,不允许外部修改,确保了封装性
public class DocumentMemento {
private String content;
public DocumentMemento(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
发起人
备忘录模式服务的对象
提供“通过备份修改内容”和“根据内容产生备份”的功能
public class Document {
private String content;
public Document(String content) {
this.content = content;
}
public void setContent(String content) {
this.content = content;
}
public String getContent() {
return content;
}
public DocumentMemento save() {
return new DocumentMemento(this.content);
}
public void restore(DocumentMemento memento) {
this.content = memento.getContent();
}
}
管理者
负责保存多个状态,用于撤销和重做
public class History {
private Stack<DocumentMemento> history = new Stack<>();
private Stack<DocumentMemento> redoStack = new Stack<>();
public void pushMemento(DocumentMemento memento) {
history.push(memento);
redoStack.clear(); // 每次新操作时清空重做栈
}
public DocumentMemento popMemento() {
if (!history.isEmpty()) {
DocumentMemento memento = history.pop();
redoStack.push(memento);
return memento;
}
return null;
}
public DocumentMemento popRedoMemento() {
if (!redoStack.isEmpty()) {
DocumentMemento memento = redoStack.pop();
history.push(memento);
return memento;
}
return null;
}
}
客户端调用
public class History {
private Stack<DocumentMemento> history = new Stack<>();
private Stack<DocumentMemento> redoStack = new Stack<>();
public void pushMemento(DocumentMemento memento) {
history.push(memento);
redoStack.clear(); // 每次新操作时清空重做栈
}
public DocumentMemento popMemento() {
if (!history.isEmpty()) {
DocumentMemento memento = history.pop();
redoStack.push(memento);
return memento;
}
return null;
}
public DocumentMemento popRedoMemento() {
if (!redoStack.isEmpty()) {
DocumentMemento memento = redoStack.pop();
history.push(memento);
return memento;
}
return null;
}
}
优缺点
优点
1)封装性强:客户端只需要知道如何创建和恢复备忘录,而不需要关心备忘录内部的实现细节
缺点
1)内存开销大
