Qt C++ 设计模式->备忘录模式
备忘录模式(Memento Pattern)是一种行为型设计模式,用于在不破坏封装性的前提下,捕获并保存对象的内部状态,以便在将来的某个时刻可以恢复到之前的状态。备忘录模式的核心是状态的保存和恢复,常用于实现撤销、回滚等功能。
备忘录模式的应用场景
备忘录模式特别适合以下场景:
-
撤销/恢复操作:例如文本编辑器中的撤销功能,通过备忘录保存每次操作的状态,用户可以随时回到某个历史状态。
-
数据快照:保存对象在某个时刻的快照,以便之后回溯或调试。
-
事务管理:在处理复杂的事务时,可以在中间点保存状态,当某个操作失败时,回滚到之前的状态。
备忘录模式的核心
备忘录模式的主要组成部分包括:
-
发起者(Originator):负责创建并恢复备忘录,保存当前的状态到备忘录中,或者从备忘录中恢复状态。
-
备忘录(Memento):用于存储发起者的内部状态,不对外公开备忘录的实现细节。
-
负责人(Caretaker):负责保存和管理备忘录,但不会操作或修改备忘录的内容。它只知道备忘录保存的状态,并在需要时将备忘录传递回发起者进行状态恢复。
备忘录模式强调的是封装性,发起者的内部状态不应该对外暴露,备忘录类也应该避免暴露这些细节。
备忘录模式的示例代码
假设我们在开发一个文本编辑器,并希望提供撤销和恢复功能,每当用户输入一段文本时,我们将保存当前状态,以便用户可以随时撤销操作。
1. 定义发起者、备忘录和负责人
#include <QDebug>
#include <QString>
#include <QStack>
// 备忘录类:保存文本编辑器的状态
class Memento {
private:
QString state; // 保存的状态
public:
Memento(const QString& state) : state(state) {}
QString getState() const {
return state; // 返回保存的状态
}
};
// 发起者类:文本编辑器
class TextEditor {
private:
QString text; // 当前的文本状态
public:
void setText(const QString& newText) {
text = newText;
}
QString getText() const {
return text;
}
// 创建备忘录,保存当前状态
Memento* save() const {
return new Memento(text);
}
// 从备忘录中恢复状态
void restore(Memento* memento) {
if (memento) {
text = memento->getState();
}
}
};
// 负责人类:管理备忘录
class Caretaker {
private:
QStack<Memento*> history; // 保存备忘录的栈
public:
void saveMemento(Memento* memento) {
history.push(memento); // 保存当前状态的备忘录
}
Memento* undo() {
if (!history.isEmpty()) {
Memento* lastState = history.pop(); // 取出最后一个保存的备忘录
return lastState;
}
return nullptr; // 没有更多历史状态
}
~Caretaker() {
// 清理保存的备忘录
while (!history.isEmpty()) {
delete history.pop();
}
}
};
// 使用示例
int main() {
TextEditor* editor = new TextEditor();
Caretaker* caretaker = new Caretaker();
// 初始文本
editor->setText("Hello");
qDebug() << "Current text:" << editor->getText(); // 输出:Current text: Hello
// 保存状态
caretaker->saveMemento(editor->save());
// 用户修改文本
editor->setText("Hello, World");
qDebug() << "Current text after modification:" << editor->getText(); // 输出:Current text after modification: Hello, World
// 再次保存状态
caretaker->saveMemento(editor->save());
// 用户再次修改文本
editor->setText("Hello, Qt!");
qDebug() << "Current text after second modification:" << editor->getText(); // 输出:Current text after second modification: Hello, Qt!
// 执行撤销操作
editor->restore(caretaker->undo());
qDebug() << "Current text after undo:" << editor->getText(); // 输出:Current text after undo: Hello, World
// 再次执行撤销操作
editor->restore(caretaker->undo());
qDebug() << "Current text after second undo:" << editor->getText(); // 输出:Current text after second undo: Hello
// 清理内存
delete editor;
delete caretaker;
return 0;
}
代码解析
-
Memento类:这是备忘录类,负责保存发起者的状态。在这个例子中,它保存文本编辑器中的文本状态,并通过
getState
方法提供对状态的访问。 -
TextEditor类:这是发起者类,它拥有当前的文本状态,并且可以创建备忘录来保存当前状态或从备忘录中恢复状态。
-
Caretaker类:这是负责人类,它保存所有的备忘录(通过栈存储历史状态),并在需要时将备忘录返回给发起者进行状态恢复。
undo
方法从栈中弹出最后保存的状态,模拟撤销操作。 -
客户端代码:客户端通过修改文本,并在每次修改后保存状态。通过调用
Caretaker
的undo
方法,客户端可以恢复到之前的文本状态,模拟撤销操作。
备忘录模式的优点
-
保存历史状态:备忘录模式允许你保存对象的状态,并在将来恢复这些状态。非常适合实现撤销、恢复、回滚等功能。
-
封装性好:备忘录类不暴露发起者的内部状态,保证了发起者的封装性。发起者和负责人只通过备忘录进行状态的保存和恢复,而不需要直接操作发起者的状态。
-
减少耦合:负责人只负责保存和管理备忘录,而不直接参与发起者的逻辑,职责清晰。
备忘录模式的缺点
-
内存开销大:每次保存对象的状态都需要创建一个新的备忘录对象,尤其是当对象状态非常庞大时,可能会导致大量的内存占用。
-
实现复杂性:如果对象的状态非常复杂,备忘录模式的实现也会相应复杂,尤其是在需要保存多个部分或大对象时。
适合使用备忘录模式的情况
-
需要实现撤销/恢复操作:例如文本编辑器、绘图工具、IDE等支持撤销/恢复功能的应用程序。
-
需要保存对象的历史状态:当系统需要定期保存某些对象的状态以便将来回溯时,可以使用备忘录模式。
-
需要避免直接暴露内部状态:如果需要在多个地方保存对象的状态,但不想让外界直接访问或修改对象的内部状态,备忘录模式是一个很好的选择。
不适合使用备忘录模式的情况
-
对象状态非常庞大:如果发起者的状态非常庞大,频繁创建备忘录会带来较大的内存开销,不适合使用备忘录模式。
-
状态变化频繁:如果对象状态变化频繁,并且每次都需要保存,那么备忘录模式会带来大量性能问题。
Qt中的备忘录模式应用
在Qt开发中,备忘录模式可以用于实现撤销/恢复功能。例如,在一个文本编辑器或绘图工具中,用户的每次操作都可能改变对象的状态,这些操作可以通过备忘录模式保存下来,并在需要时回滚或恢复。Qt中有些类(如QUndoStack
)可以直接实现类似的撤销功能,它们内部也可能应用了备忘录模式的思想。
总结
备忘录模式通过保存对象的状态并在将来进行恢复,使得系统能够实现撤销、回滚等功能,同时保证了对象内部状态的封装性。它非常适合用于保存对象的历史状态、支持撤销操作的场景。然而,备忘录模式的内存开销较大,不适合频繁状态变化且状态庞大的对象。
上一篇: 1.stm32 新项目
下一篇: 什么是流光溢彩