目录
备忘录模式【Memento Pattern】,什么是备忘录模式?工作原理?优缺点?主要角色?使用场景?实现案例?
什么是备忘录模式?
备忘录模式(Memento Pattern)是一种行为设计模式,用于在不破坏封装性的前提下捕获和恢复对象的内部状态。通过保存对象的状态快照,备忘录模式允许我们在未来的某个时刻将对象恢复到之前的状态,通常用于实现撤销和恢复功能。
备忘录模式工作原理
(1)原发器创建一个备忘录,保存其当前状态。
(2)备忘录被传递给管理者进行存储,但管理者不会修改或检查备忘录的内容。
(3)当需要恢复时,管理者将备忘录还给原发器,原发器利用备忘录恢复之前的状态。
备忘录模式优缺点
优点
(1)保持封装性
备忘录模式确保了对象的内部状态不被外部对象直接访问,原发器对象可以完全控制状态的保存和恢复。
(2)支持撤销/恢复操作
备忘录模式可以方便地实现撤销和恢复功能,特别是在文本编辑器、事务处理系统等场景中。
(3)灵活性
可以保存任意数量的状态快照,管理者可以根据需要选择存储和删除快照。
缺点
(1)内存开销大
如果对象状态很复杂,频繁保存备忘录可能导致较高的内存开销。
(2)管理复杂
需要管理多个备忘录的存储和恢复,这可能会使系统变得复杂。
备忘录模式主要角色
(1)备忘录(Memento)
用于存储对象的内部状态。它只暴露给原发器对象,其他对象不能直接访问备忘录的状态。
(2)原发器(Originator)
创建包含其当前状态的备忘录,并能够使用备忘录恢复其状态。它是存储和恢复状态的实际对象。
(3)管理者(Caretaker)
负责保存备忘录,但不能修改或访问备忘录的内容。它只知道如何将备忘录传递回原发器,以便在需要时恢复状态。
备忘录模式使用场景
(1)需要保存和恢复对象的历史状态
例如:撤销和重做功能,如文本编辑器中的“撤销”操作。
(2)希望不暴露对象的内部状态
当你想要保存和恢复对象的状态,但又不想破坏对象的封装性时,备忘录模式是一个很好的选择。
(3)需要进行事务回滚
在数据库事务或其他重要的操作中,备忘录模式可以保存某一时刻的状态,以便在出现错误时回滚到之前的状态。
备忘录模式实现案例
创建一个简单的文本编辑器,它能够:
(1)编辑文本内容。
(2)保存多个状态快照。
(3)撤销和恢复文本到之前的某个状态。
(1)备忘录(Memento)
Memento 类保存了文本编辑器的当前状态,状态存储在 String 类型的变量中。提供 getState() 方法用于让原发器恢复到之前的状态。
package com.uhhe.common.design.memento;
/**
* 备忘录:用于存储文本编辑器的状态
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/6 23:42
*/
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
(2)文本编辑器(原发器,Originator)
TextEditor 类代表文本编辑器,负责修改和保存文本,并通过 save() 方法生成备忘录,通过 restore() 方法从备忘录恢复之前的状态。
package com.uhhe.common.design.memento;
/**
* 原发器:文本编辑器,保存文本并生成备忘录
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/6 23:43
*/
public class TextEditor {
private StringBuilder text = new StringBuilder();
/**
* 编辑文本
*
* @param words 添加文字
*/
public void type(String words) {
text.append(words);
}
/**
* 获取当前文本内容
* @return 当前文本
*/
public String getText() {
return text.toString();
}
/**
* 保存当前状态到备忘录
* @return Memento 备忘录
*/
public Memento save() {
return new Memento(text.toString());
}
/**
* 从备忘录中恢复之前的状态
*
* @param memento 备忘录
*/
public void restore(Memento memento) {
text = new StringBuilder(memento.getState());
}
}
(3)保存和管理备忘录的历史记录(管理者,Caretaker)
Caretaker 类负责管理保存的备忘录,并通过 saveMemento() 保存状态,通过 undo() 方法从历史记录中撤销到之前的状态。
package com.uhhe.common.design.memento;
import java.util.ArrayList;
import java.util.List;
/**
* 管理者:保存和管理备忘录的历史记录
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/6 23:45
*/
public class Caretaker {
private List<Memento> mementoList = new ArrayList<>();
/**
* 保存备忘录
*
* @param memento 备忘录
*/
public void saveMemento(Memento memento) {
mementoList.add(memento);
}
/**
* 撤销:恢复到上一个状态
* @return 上一个Memento
*/
public Memento undo() {
if (mementoList.size() > 0) {
return mementoList.remove(mementoList.size() - 1);
}
return null;
}
}
(4)客户端使用备忘录
package com.uhhe.common.design.memento;
/**
* 客户端使用备忘录
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/6 23:46
*/
public class MementoPatternDemo {
public static void main(String[] args) {
TextEditor editor = new TextEditor();
Caretaker caretaker = new Caretaker();
// 编辑并保存状态
editor.type("Hello, ");
caretaker.saveMemento(editor.save());
editor.type("World! ");
caretaker.saveMemento(editor.save());
editor.type("Let's write some Java code.");
System.out.println("当前文本内容: " + editor.getText());
// 撤销操作
editor.restore(caretaker.undo());
System.out.println("撤销一次后的文本内容: " + editor.getText());
editor.restore(caretaker.undo());
System.out.println("再撤销一次后的文本内容: " + editor.getText());
Memento lastState = caretaker.undo();
if (lastState == null) {
System.out.println("没有更多的撤销操作!");
}
}
}
总结:Java实现的备忘录模式展示了如何通过保存对象状态的快照来实现撤销和恢复功能。通过 Caretaker 管理状态历史,确保原发器的封装性得以保持,并为实现复杂系统中的撤销和恢复功能提供了便捷的手段。