在备忘录模式的笼罩下,记忆成了静静的落英,沉淀在岁月的琐碎中。
一、无法撤销的编辑器
场景假设:我们需要使用一个简单的文本编辑器进行写作。在写作过程中,可能会不断地添加新的内容,也可能会删除一些已经写好的内容。
public class Editor {
private StringBuilder content = new StringBuilder();
// 输入文字
public void type(String words) {
content.append(words);
}
// 删除文字
public void deleteLast() {
if (content.length() > 0) {
content.deleteCharAt(content.length() - 1);
}
}
// 获取当前内容
public String getContent() {
return content.toString();
}
}
public class Main {
public static void main(String[] args) {
Editor editor = new Editor();
// 输入一些文字
editor.type("这是第一句。");
editor.type("这是第二句。");
// 删除最后一个字符
editor.deleteLast();
// 输出:删除后的内容
System.out.println(editor.getContent()); // 这是第一句。这是第二句
// 我们现在无法撤销删除操作,因为我们没有保存状态的机制
}
}
如果我们使用上面的文本编辑器,可能会遇到一个问题:如果误删了一些内容,我们可能会希望能够撤销这个删除操作,恢复到删除前的状态。但是,这个文本编辑器没有提供撤销功能,那么就无法恢复到删除前的状态。
二、备忘录模式
备忘录模式(Memento Pattern)是一种行为型
设计模式,它允许在不破坏封装的情况下捕获一个对象的内部状态,并在该对象之外保存这个状态,以便在将来某个时候将对象恢复到先前保存的状态。备忘录模式通常用于需要记录对象状态历史、实现撤销操作或者实现事务性回滚的情况。
三、备忘录模式的核心组件
备忘录模式的核心组件包括以下几个角色:
- 发起人(Originator):
- 发起人是拥有需要被保存状态的对象。
- 发起人负责创建备忘录对象,记录当前的内部状态,或者从备忘录对象中恢复状态。
- 备忘录(Memento):
- 备忘录是存储发起人对象内部状态的对象。
- 备忘录对象通常包含了发起人对象在某个时刻的全部或部分状态。
- 备忘录对象应该只能由发起人访问,保证了状态的封装性。
- 管理者(Caretaker):
- 管理者是负责保存备忘录对象的对象。
- 管理者不应该直接操作备忘录对象的内容,它的主要职责是存储和提供备忘录对象给发起人对象。
在上述类图中:
- Originator 类有一个私有状态(
state
),它负责创建备忘录对象(createMemento()
)来保存当前状态,以及通过备忘录对象恢复状态(restoreMemento()
)。 - Memento 类包含一个私有状态(
state
),并提供了访问和设置状态的方法(getState()
和setState()
)。它是发起人对象内部状态的快照。 - Caretaker 类负责管理备忘录对象的列表(
mementoList
),它可以添加新的备忘录对象(addMemento()
)和获取特定索引处的备忘录对象(getMemento()
)。管理者在这里起到了保存和管理备忘录对象的作用。
四、运用备忘录模式
场景假设:我们需要开发一个简单的文本编辑器进行写作。这个文本编辑器除了基础功能之外还需要额外需要提供撤销功能。
-
创建发起人(Originator):发起人是一个有状态的对象,它可以创建一个备忘录来保存其内部状态,并可以使用备忘录来恢复其内部状态。
public class Editor { private StringBuilder content = new StringBuilder(); // 输入文字 public void type(String words) { content.append(words); } // 创建备忘录 public Memento save() { return new Memento(content.toString()); } // 恢复到备忘录保存的状态 public void restore(Memento memento) { content = new StringBuilder(memento.getContent()); } }
-
创建备忘录(Memento):备忘录是一个用于保存原发器状态的对象。备忘录只能被原发器访问和修改。
public class Memento { private final String content; public Memento(String content) { this.content = content; } public String getContent() { return content; } }
-
创建管理者(Caretaker):管理者负责保存备忘录,但不能对备忘录的内容进行操作或检查。
public class Caretaker { private Memento memento; public void saveState(Editor editor) { memento = editor.save(); } public void undo(Editor editor) { if (memento != null) { editor.restore(memento); } } }
-
使用备忘录模式:在需要保存状态的时候,调用发起人的
save
方法创建备忘录,并由管理者保存;在需要恢复状态的时候,由管理者调用发起人的restore
方法恢复到备忘录保存的状态。public class Main { public static void main(String[] args) { Editor editor = new Editor(); Caretaker caretaker = new Caretaker(); // 输入一些文字 editor.type("这是第一句。"); editor.type("这是第二句。"); // 保存状态 caretaker.saveState(editor); // 删除最后一个字符 editor.deleteLast(); // 输出:删除后的内容 System.out.println(editor.getContent()); // 这是第一句。这是第二句 // 撤销删除操作,恢复到保存的状态 caretaker.undo(editor); // 输出:恢复后的内容 System.out.println(editor.getContent()); // 这是第一句。这是第二句。 } }
五、备忘录模式的应用场景
备忘录模式在许多场景中都非常有用,特别是在需要保存和恢复状态的情况下。以下是一些常见的应用场景:
- 文本编辑器:在文本编辑器中,我们经常需要使用撤销(undo)和重做(redo)操作。备忘录模式可以用来保存每次编辑后的状态,然后在需要的时候恢复到之前的状态。
- 游戏:在许多游戏中,玩家可能需要保存游戏进度,以便在以后的某个时间点继续游戏。备忘录模式可以用来保存游戏的状态,包括玩家的位置、得分、生命值等。
- 软件版本控制:在软件版本控制系统(如 Git)中,备忘录模式可以用来保存每次提交的状态,然后在需要的时候恢复到之前的状态。
- 数据库事务管理:在数据库事务管理中,如果一个事务在执行过程中出错,我们可能需要回滚(rollback)事务,即恢复到事务开始时的状态。备忘录模式可以用来保存事务开始时的状态。
- 图形编辑器:在图形编辑器中,用户可能会进行一系列的编辑操作,如旋转、缩放、裁剪等。如果用户不满意编辑的结果,可能需要撤销一系列的操作。备忘录模式可以用来保存每次编辑操作后的状态。
六、小结
备忘录模式通过将对象状态保存在备忘录对象中,并由管理者管理备忘录对象,实现了对象状态的保存和恢复功能。它提高了系统的灵活性和可维护性,特别适用于需要撤销操作或者保存历史记录的场景。