🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!
前言
设计模式是软件设计中经典的解决方案,旨在解决软件开发中常见的问题。备忘录模式(Memento
)是其中一种经典的设计模式,它允许在不破坏封装的前提下,保存和恢复对象的内部状态。在本文中,我们将深入了解备忘录模式的实现和应用。
摘要
备忘录模式是一种行为型设计模式,它能够在不破坏对象封装的情况下,保存和恢复对象的内部状态。在备忘录模式中,我们可以将需要保存的对象状态封装到备忘录对象中,并将备忘录对象存储在一个称为管理者的对象中,以便稍后通过管理者对象恢复状态。
备忘录模式
概念
备忘录模式是一种行为型设计模式,它允许在不暴露对象实现细节的情况下获取对象状态的全部或部分,并将该状态保存在一个备忘录对象中以便于稍后恢复对象状态。这种模式的核心是备忘录对象,它存储了对象的状态信息,同时提供了对该状态信息的访问和恢复操作。备忘录模式通常用于实现撤销和重做功能,在许多编辑器、文本处理器和图形编辑器等应用程序中都有广泛的应用。
结构
备忘录模式由三个主要组件组成:
- 发起人(
Originator
):它是需要备份和恢复状态的对象。它存储它自己的内部状态,并且可以创建和恢复备忘录对象。 - 备忘录(
Memento
):它存储了发起人对象的内部状态。尽管备忘录具有发起人的状态信息,但是它无法被除了发起人之外的其他对象访问。 - 管理者(
Caretaker
):它负责存储备忘录并提供对备忘录的访问。管理者对象可以存储多个备忘录对象,并可用于恢复先前保存的状态。
如下是备忘录模式的UML类图:
以下是备忘录模式的实现,我们以一个存储文本编辑器历史记录的例子为例:
//备忘录对象
public class TextEditorMemento {
private final String text;
public TextEditorMemento(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
// 发起人对象
public class TextEditor {
private String text;
public TextEditor() {
this.text = "";
}
public void setText(String text) {
this.text = text;
}
public TextEditorMemento createMemento() {
return new TextEditorMemento(text);
}
public void restoreMemento(TextEditorMemento memento) {
this.text = memento.getText();
}
}
// 管理者对象
public class TextEditorHistory {
private List history = new ArrayList();
public void push(TextEditorMemento memento) {
history.add(memento);
}
public TextEditorMemento pop() {
return history.remove(history.size() - 1);
}
}
在这个例子中,TextEditor
是发起人对象,它负责存储文本编辑器的当前文本,并提供方法 createMemento()
和 restoreMemento(TextEditorMemento memento)
来创建备忘录和恢复备忘录。备忘录对象 TextEditorMemento
存储了文本编辑器的文本内容。管理者对象 TextEditorHistory
负责存储备忘录,并提供操作备忘录的方法 push(TextEditorMemento memento)
和 pop()
。
以下是备忘录模式的应用场景:
- 当需要保存和恢复对象的一部分或全部状态时。
- 当直接访问对象状态会导致封装被破坏时。
- 当需要保存对象的历史快照或可撤销操作历史记录时。
应用场景
备忘录模式(Memento Pattern
)在面向对象设计中被广泛应用,其主要作用是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,从而可以在需要的时候将对象恢复到先前的状态。
下面是一些备忘录模式的应用场景:
撤销操作:在许多应用程序中,用户执行操作时需要有“撤销”操作。通过备忘录模式,可以在执行操作前将当前对象的状态保存到备忘录中,当需要撤销时,从备忘录中获取之前保存的状态并恢复对象。
数据库事务回滚:在数据库系统中,事务是一组被视为一个单独工作单元的操作。在执行事务时,如果发生了错误,需要将整个事务回滚到最初的状态。备忘录模式可以用来实现这种回滚,将事务执行前的状态保存到备忘录中,当出现错误时可以从备忘录中恢复原始状态。
游戏存档:在许多游戏中,玩家需要保存游戏进度,以便在之后的时间里恢复到该点。备忘录模式可以用来保存游戏状态,让玩家在需要时回到先前的状态。
操作系统恢复:当操作系统出现错误或崩溃时,需要将系统的状态恢复到某个先前的时间点。备忘录模式可以利用系统快照机制,将系统的状态保存到备忘录中,从而实现系统恢复。
总之,备忘录模式在许多应用程序中都有着广泛的应用,其主要作用是在不破坏封装性的前提下,捕获对象的内部状态,以便将来可以恢复对象到先前的状态。
优缺点
优点:
备忘录模式的优点如下:
缺点:
备忘录模式的缺点如下:
模式实现
TextEditorMemento
package com.example.javaDesignPattern.memento;
/**
* @author bug菌
* @version 1.0
* @date 2023/9/20 11:21
*/
public class TextEditorMemento {
private final String text;
public TextEditorMemento(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
TextEditorMemento
是备忘录对象,它存储了文本编辑器的文本内容。它具有一个字符串类型的 text
属性和方法 getText()
用于获取 text
属性的值。
TextEditor
package com.example.javaDesignPattern.memento;
/**
* @author bug菌
* @version 1.0
* @date 2023/9/20 11:22
*/
public class TextEditor {
private String text;
public TextEditor() {
this.text = "";
}
public void setText(String text) {
this.text = text;
}
public String getText() {
return text;
}
public TextEditorMemento createMemento() {
return new TextEditorMemento(text);
}
public void restoreMemento(TextEditorMemento memento) {
this.text = memento.getText();
}
}
TextEditor
是发起人对象,它负责存储文本编辑器的当前文本,并提供方法 createMemento()
和 restoreMemento(TextEditorMemento memento)
来创建备忘录和恢复备忘录。它具有一个字符串类型的 text
属性和方法 setText(String text)
用于设置 text
属性的值。
TextEditor()
: 构造方法,初始化text
为 ""。void setText(String text)
: 设置text
属性的值。TextEditorMemento createMemento()
: 创建备忘录对象并返回,它将text
属性存储在备忘录中。void restoreMemento(TextEditorMemento memento)
: 从备忘录中恢复text
属性的值。
TextEditorHistory
package com.example.javaDesignPattern.memento;
import java.util.ArrayList;
import java.util.List;
/**
* @author bug菌
* @version 1.0
* @date 2023/9/20 11:22
*/
public class TextEditorHistory {
private List history = new ArrayList();
public void push(TextEditorMemento memento) {
history.add(memento);
}
public TextEditorMemento pop() {
return history.remove(history.size() - 1);
}
}
TextEditorHistory
是管理者对象,它负责存储备忘录,并提供操作备忘录的方法 push(TextEditorMemento memento)
和 pop()
。它具有一个 history
属性,它用于存储备忘录对象列表。
void push(TextEditorMemento memento)
: 将备忘录添加到history
中。TextEditorMemento pop()
: 从history
中删除并返回最近添加的备忘录。
测试用例
public class MementoPatternTest {
@Test
public void testMementoPattern() {
TextEditor editor = new TextEditor();
TextEditorHistory history = new TextEditorHistory();
editor.setText("Hello World!");
history.push(editor.createMemento());
editor.setText("Goodbye World!");
history.push(editor.createMemento());
editor.restoreMemento(history.pop());
assertEquals(editor.getText(), "Goodbye World!");
editor.restoreMemento(history.pop());
assertEquals(editor.getText(), "Hello World!");
}
}
执行结果如下所示:
在这个测试用例中,我们首先创建了一个文本编辑器对象和一个历史记录对象。接下来,我们设置文本编辑器的文本为Hello World!
,创建备忘录,并将备忘录添加到历史记录中。然后我们更新文本编辑器的文本为 Goodbye World!
,创建备忘录,并将备忘录添加到历史记录中。最后,我们将文本编辑器恢复到先前的状态,并验证其文本是否正确。
测试用例代码解析
这段代码是一个单元测试,在使用Memento
设计模式实现的TextEditor
类中,测试了从历史记录(TextEditorHistory
)中恢复(TextEditor.restoreMemento
)已保存的文本(TextEditor.createMemento
)的功能。
具体来说,测试分为以下步骤:
- 创建
TextEditor
实例和TextEditorHistory
实例; - 调用
TextEditor.setText
方法,设置文本为"Hello World!",并通过TextEditor.createMemento方法创建一个Memento
对象,将其推入历史记录中; - 再次调用
TextEditor.setText
方法,设置文本为Goodbye World!
,并将其推入历史记录中; - 调用历史记录的
TextEditorHistory.pop
方法获取最后一个保存的Memento
对象,并通过TextEditor.restoreMemento
方法将其恢复为之前存储的状态,即Goodbye World!
; - 再次调用历史记录的
TextEditorHistory.pop
方法获取上一个保存的Memento
对象,并通过TextEditor.restoreMemento
方法将其恢复为之前存储的状态,即Hello World!
; - 使用
JUnit
的assertEquals
方法来比较恢复后的文本是否与预期相同。
这个测试用例确保了Memento
模式在TextEditor
类中正确地实现。
小结
备忘录模式是一种行为型设计模式,它允许在不破坏对象封装的情况下,保存和恢复对象的内部状态。在备忘录模式中,我们可以将需要保存的对象状态封装到备忘录对象中,并将备忘录对象存储在一个称为管理者的对象中,以便稍后通过管理者对象恢复状态。
备忘录模式的主要组件包括发起人对象、备忘录对象和管理者对象。发起人对象是需要备份和恢复状态的对象,它存储它自己的内部状态,并且可以创建和恢复备忘录对象。备忘录对象存储了发起人对象的内部状态。
附录源码
如上涉及代码均已上传同步在GitHub,提供给同学们参考性学习。
总结
备忘录模式是一种行为型设计模式,其核心在于在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,从而可以在需要的时候将对象恢复到先前的状态。备忘录模式由发起人、备忘录和管理者三种角色组成,其中发起人是需要备份和恢复状态的对象;备忘录是存储发起人对象内部状态的对象;管理者负责存储备忘录并提供对备忘录的访问。
备忘录模式的优点在于分离了数据与操作,实现了撤销和恢复功能以及比较灵活;缺点在于可能会占用较大的内存空间,增加了程序的复杂度,以及可能会影响程序的性能。备忘录模式应用广泛,例如实现撤销操作、数据库事务回滚、游戏存档以及操作系统恢复等。
☀️建议/推荐你
如果想系统性的全面学习设计模式,建议小伙伴们直接毫无顾忌的关注这个专栏《聊设计模式》,无论你是想提升自己的编程技术,还是渴望更好地理解代码背后的设计思想,本专栏都会为你提供实用的知识和启发,帮助你更好地解决日常开发中的挑战,将代码变得更加优雅、灵活和可维护!
最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。
同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。
📣关于我
我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。