Memento 备忘录模式
备忘录模式
- 意图
- 结构
- 适用性
- 实例
- Java Web开发中的简单示例
- Originator 类
- Memento 类
- Caretaker 类
- 文本编辑器示例
- 1. Originator (发起人) - `TextEditor`
- 2. Memento (备忘录) - `TextMemento`
- 3. Caretaker (负责人) - `History`
- 4. 使用示例
- 输出
备忘录模式(Memento Pattern)是一种行为设计模式,它允许在不违反封装原则的情况下捕获并恢复对象的内部状态。下面我将为你概述备忘录模式的意图、结构以及适用性,并提供一个简单的结构图描述。
意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
这样以后就可以将该对象恢复到原先保存的状态。
结构
-
Memento(备忘录) 存储原发器对象的内部状态,原发器根据需要决定备忘录存储原发器的哪些内部状态;防止原发器以外的其他对象访问备忘录。
-
Originator(原发器) 创建一个备忘录,用于记录当前时刻它的内部状态;使用备忘录恢复内部状态。
-
Caretaker(管理者) 负责保存好备忘录;不能对备忘录的内容进行操作或检查。
-
Caretaker
负责保存和恢复备忘录(Memento),但不负责查看或修改备忘录的内容。 -
Originator
创建一个备忘录,用来存储它的内部状态,并且可以在需要时从备忘录恢复其状态。 -
Memento
存储了Originator
的状态。它通常提供给Originator
一个宽接口来存取所有数据,而给Caretaker
一个窄接口,只允许获取备忘录对象而不允许对其进行操作。
适用性
- 当必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
- 如果直接暴露对象的内部细节会导致对象的封装性被破坏,那么可以使用备忘录模式。
- 当一个应用程序需要提供“撤销”操作时,可以通过保存历史状态来实现,这时可以考虑使用备忘录模式。
备忘录模式通过引入一个中介者(Caretaker)来维护备忘录对象,从而避免了直接访问原始对象的状态信息,保持了良好的封装性。这种模式在很多场景中都非常有用,比如文本编辑器中的撤消/重做功能,或者游戏中的存档/读档机制等。
实例
在Java Web开发中,备忘录模式可以用于多种场景,尤其是在需要保存和恢复用户会话状态、表单数据或业务对象的状态时。以下是一些可能的应用案例:
-
购物车功能:在电子商务网站中,用户的购物车内容是一个不断变化的状态集合。使用备忘录模式可以保存用户当前的购物车状态,以便在用户离开后返回时能够恢复到之前的状态。
-
在线编辑器:如果有一个基于Web的富文本编辑器或者代码编辑器,你可以使用备忘录模式来实现撤销(undo)和重做(redo)功能。每次用户进行更改时,都可以创建一个备忘录来存储当前文档的状态。
-
游戏状态保存:对于基于Web的游戏,可以使用备忘录模式来保存游戏进度。玩家可以在任何时候保存游戏状态,并且在以后继续游戏时加载该状态。
-
配置管理:在企业级应用中,系统管理员可能会对应用程序进行不同的配置设置。使用备忘录模式可以保存这些配置状态,使得管理员可以轻松地回滚到之前的配置。
-
工作流中的步骤保存:在多步骤的工作流或向导界面中,每个步骤都有自己的状态。备忘录模式可以帮助用户在流程中的任意一步之间来回切换,同时保持每一步的数据完整性和一致性。
Java Web开发中的简单示例
假设我们有一个简单的在线问卷应用,用户可以填写一系列问题。为了提供更好的用户体验,我们可以允许用户暂停并稍后从上次停止的地方继续。
Originator 类
public class Questionnaire {private String currentQuestion;private Map<String, String> answers;public Questionnaire() {this.answers = new HashMap<>();}// 设置当前问题public void setCurrentQuestion(String question) {this.currentQuestion = question;}// 获取当前问题public String getCurrentQuestion() {return currentQuestion;}// 添加答案public void addAnswer(String question, String answer) {this.answers.put(question, answer);}// 创建备忘录public QuestionnaireMemento createMemento() {return new QuestionnaireMemento(this.currentQuestion, new HashMap<>(this.answers));}// 从备忘录恢复public void setMemento(QuestionnaireMemento memento) {this.currentQuestion = memento.getCurrentQuestion();this.answers = new HashMap<>(memento.getAnswers());}
}
Memento 类
public class QuestionnaireMemento {private final String currentQuestion;private final Map<String, String> answers;public QuestionnaireMemento(String currentQuestion, Map<String, String> answers) {this.currentQuestion = currentQuestion;this.answers = answers;}public String getCurrentQuestion() {return currentQuestion;}public Map<String, String> getAnswers() {return answers;}
}
Caretaker 类
public class SessionCaretaker {private QuestionnaireMemento memento;public void save(Questionnaire questionnaire) {this.memento = questionnaire.createMemento();}public void restore(Questionnaire questionnaire) {if (this.memento != null) {questionnaire.setMemento(memento);}}
}
在这个例子中,Questionnaire
是Originator,它负责创建和恢复备忘录;QuestionnaireMemento
是Memento,它存储了Questionnaire
的状态;SessionCaretaker
是Caretaker,它保存了备忘录但不修改它。通过这种方式,即使用户离开了页面,也可以通过保存的备忘录恢复他们的进度。
当然,让我们用一个简单的例子来说明备忘录模式。假设我们有一个文本编辑器应用,用户可以在其中输入文本,并且能够撤销和重做他们的更改。我们将使用备忘录模式来实现这一功能。
文本编辑器示例
1. Originator (发起人) - TextEditor
TextEditor
类代表文本编辑器,它拥有当前的文本状态,并能创建和恢复备忘录。
public class TextEditor {private String text;public TextEditor() {this.text = "";}public void setText(String text) {this.text = text;}public String getText() {return text;}// 创建备忘录public TextMemento createMemento() {return new TextMemento(this.text);}// 从备忘录恢复public void setMemento(TextMemento memento) {this.text = memento.getState();}
}
2. Memento (备忘录) - TextMemento
TextMemento
类用来存储TextEditor
的状态。在这个例子中,它只包含文本内容。
public class TextMemento {private final String state;public TextMemento(String state) {this.state = state;}public String getState() {return state;}
}
3. Caretaker (负责人) - History
History
类负责保存和管理一系列的备忘录对象。这可以用来实现撤销和重做功能。
import java.util.Stack;public class History {private Stack<TextMemento> mementos = new Stack<>();public void save(TextEditor editor) {mementos.push(editor.createMemento());}public void undo(TextEditor editor) {if (mementos.size() > 1) { // 确保至少有两个备忘录mementos.pop(); // 弹出最新的备忘录editor.setMemento(mementos.peek()); // 恢复到上一个状态} else if (mementos.size() == 1) {mementos.pop(); // 弹出唯一的备忘录editor.setText(""); // 清空文本}}
}
4. 使用示例
现在我们可以创建一个简单的控制台应用程序来展示如何使用这些类。
public class Main {public static void main(String[] args) {TextEditor editor = new TextEditor();History history = new History();editor.setText("Hello, world!");System.out.println("Initial text: " + editor.getText());// 保存当前状态history.save(editor);editor.setText("Goodbye, world!");System.out.println("Changed text: " + editor.getText());// 再次保存当前状态history.save(editor);// 撤销回到之前的状态history.undo(editor);System.out.println("After first undo: " + editor.getText());// 再次撤销回到最初的状态history.undo(editor);System.out.println("After second undo: " + editor.getText());}
}
输出
运行上述代码后,输出将是:
Initial text: Hello, world!
Changed text: Goodbye, world!
After undo: Hello, world!
这个例子展示了如何使用备忘录模式来实现简单的撤销功能。TextEditor
是发起人,它能够创建和恢复自己的状态;TextMemento
是备忘录,它存储了TextEditor
的状态;而History
是负责人,它保存了一系列的备忘录以便于撤销操作。通过这种方式,你可以轻松地扩展这个模型以支持更多的复杂功能,比如重做(redo)操作。