C++实现设计模式---备忘录模式 (Memento)
备忘录模式 (Memento)
备忘录模式 是一种行为型设计模式,它允许在不破坏封装的前提下,捕获和恢复对象的内部状态。通过备忘录模式,可以在程序运行时存储某个对象的历史状态,并在需要时恢复。
意图
- 提供一种方法,在不破坏对象封装性的前提下捕获和恢复其内部状态。
- 通过备忘录存储对象的历史状态,便于实现撤销、重做功能。
使用场景
- 需要保存对象的历史状态:
- 如文本编辑器中的撤销、恢复功能。
- 需要在程序运行时回滚对象状态:
- 如游戏中存储和恢复玩家进度。
- 希望避免暴露对象的实现细节:
- 通过备忘录隐藏对象的内部状态。
参与者角色
- 发起人 (Originator)
- 定义一个创建和恢复备忘录的接口,负责存储对象的内部状态。
- 备忘录 (Memento)
- 存储发起人对象的内部状态。
- 对发起人以外的其他对象是不可变的。
- 管理者 (Caretaker)
- 负责保存和恢复备忘录,但无法访问备忘录的内容。
示例代码
以下代码展示了备忘录模式的实现,用于模拟一个文本编辑器的撤销和恢复功能。
#include <iostream>
#include <string>
#include <vector>
#include <memory>
// 备忘录类:存储文本状态
class Memento {
private:
std::string state;
public:
explicit Memento(const std::string& state) : state(state) {}
std::string getState() const {
return state;
}
};
// 发起人类:文本编辑器
class TextEditor {
private:
std::string text;
public:
void appendText(const std::string& newText) {
text += newText;
}
void setText(const std::string& newText) {
text = newText;
}
std::string getText() const {
return text;
}
// 创建备忘录
std::unique_ptr<Memento> save() const {
return std::make_unique<Memento>(text);
}
// 恢复状态
void restore(const Memento& memento) {
text = memento.getState();
}
};
// 管理者类:管理备忘录
class Caretaker {
private:
std::vector<std::unique_ptr<Memento>> history;
public:
void save(std::unique_ptr<Memento> memento) {
history.push_back(std::move(memento));
}
const Memento* undo() {
if (!history.empty()) {
const Memento* memento = history.back().get();
history.pop_back();
return memento;
}
return nullptr;
}
};
// 客户端代码
int main() {
TextEditor editor;
Caretaker caretaker;
editor.appendText("Hello");
caretaker.save(editor.save()); // 保存状态
editor.appendText(", World!");
caretaker.save(editor.save()); // 保存状态
editor.appendText(" Welcome to the Memento Pattern.");
std::cout << "当前文本: " << editor.getText() << "
";
// 撤销操作
const Memento* memento = caretaker.undo();
if (memento) {
editor.restore(*memento);
std::cout << "撤销后文本: " << editor.getText() << "
";
}
memento = caretaker.undo();
if (memento) {
editor.restore(*memento);
std::cout << "再次撤销后文本: " << editor.getText() << "
";
}
return 0;
}
代码解析
1. 备忘录类 (Memento)
- 存储发起人对象的内部状态,并提供一个方法获取状态。
- 对其他对象不可变,只有发起人可以访问和修改它的内容。
class Memento {
private:
std::string state;
public:
explicit Memento(const std::string& state) : state(state) {}
std::string getState() const {
return state;
}
};
2. 发起人类 (TextEditor)
- 负责创建和恢复备忘录。
- 提供
save
方法创建备忘录和restore
方法恢复备忘录中的状态。
class TextEditor {
private:
std::string text;
public:
void appendText(const std::string& newText) {
text += newText;
}
std::unique_ptr<Memento> save() const {
return std::make_unique<Memento>(text);
}
void restore(const Memento& memento) {
text = memento.getState();
}
};
3. 管理者类 (Caretaker)
- 保存和管理备忘录对象的历史。
- 提供
save
方法保存备忘录,和undo
方法实现状态回滚。
class Caretaker {
private:
std::vector<std::unique_ptr<Memento>> history;
public:
void save(std::unique_ptr<Memento> memento) {
history.push_back(std::move(memento));
}
const Memento* undo() {
if (!history.empty()) {
const Memento* memento = history.back().get();
history.pop_back();
return memento;
}
return nullptr;
}
};
4. 客户端代码
- 客户端通过
TextEditor
创建和恢复状态,Caretaker
保存备忘录。
优缺点
优点
- 封装性:
- 备忘录对象对其他类是不可变的,保护了发起人的内部状态。
- 简化撤销/恢复操作:
- 通过备忘录存储历史状态,可以轻松实现撤销和恢复功能。
- 符合单一职责原则:
- 发起人和管理者各自负责不同的功能。
缺点
- 内存开销:
- 每次保存状态都会创建一个备忘录对象,可能占用较多内存。
- 实现复杂性:
- 需要额外的类来管理和存储备忘录。
适用场景
- 需要存储对象的历史状态:
- 如撤销功能、版本控制等场景。
- 需要恢复对象状态:
- 如游戏进度存储和恢复。
- 希望对象状态的存储和恢复对外透明:
- 通过备忘录隐藏内部实现细节。
总结
备忘录模式通过存储对象的历史状态,实现了状态的保存和恢复功能。它特别适用于需要撤销操作或恢复特定状态的场景。虽然会增加内存开销,但其封装性和操作的便利性使其在许多应用中非常有用。