备忘录模式(Memento Pattern)
目的意图
备忘录模式是一种行为设计模式,目的是在不破坏封装性的前提下,捕获并保存一个对象的内部状态,以便在之后可以将对象恢复到这个状态。备忘录模式的核心思想是将对象的状态保存到外部,这样对象可以在不暴露其内部结构的情况下被恢复。
关键角色
-
Originator(发起人):
- 这是需要保存和恢复状态的对象。
- 它创建一个备忘录(Memento)对象来存储其内部状态。
- 它可以从备忘录中恢复其状态。
-
Memento(备忘录):
- 这是存储 Originator 内部状态的对象。
- 它通常是不可变对象,防止状态被意外修改。
-
Caretaker(管理者):
- 这是负责保存和恢复备忘录的对象。
- 它不直接操作备忘录的内部状态,而是通过 Originator 来管理备忘录。
适用场合
备忘录模式适用于以下场景:
-
需要保存对象的内部状态:
- 当需要保存对象的内部状态,并在之后恢复到该状态时,备忘录模式非常有用。例如,文本编辑器中的撤销/重做功能。
-
不希望破坏对象的封装性:
- 如果直接访问对象的内部状态会导致封装性被破坏,备忘录模式可以通过封装状态保存和恢复逻辑来避免这种情况。
-
需要管理多个状态快照:
- 当需要保存多个状态快照,以便在不同时间点恢复对象时,备忘录模式可以很好地管理这些快照。例如,游戏中的存档功能。
-
状态恢复操作具有复杂性:
- 当状态恢复操作比较复杂,涉及到多个对象或多个状态时,备忘录模式可以将这些复杂的操作封装在 Originator 中,简化客户端代码。
示例代码
以下是一个简单的 C++ 示例,演示如何使用备忘录模式来实现文本编辑器的撤销功能。
cpp
#include <iostream>
#include <string>
#include <vector>
// Memento: 存储 Originator 的状态
class Memento {
public:
Memento(const std::string& state) : state(state) {}
std::string getState() const {
return state;
}
private:
std::string state;
};
// Originator: 需要保存和恢复状态的对象
class TextEditor {
public:
void setText(const std::string& text) {
this->text = text;
std::cout << "Text set to: " << text << std::endl;
}
std::string getText() const {
return text;
}
Memento save() const {
return Memento(text);
}
void restore(const Memento& memento) {
text = memento.getState();
std::cout << "Restored to text: " << text << std::endl;
}
private:
std::string text;
};
// Caretaker: 管理 Memento 对象
class History {
public:
void push(const Memento& memento) {
history.push_back(memento);
}
Memento pop() {
if (history.empty()) {
throw std::runtime_error("No more mementos!");
}
Memento memento = history.back();
history.pop_back();
return memento;
}
private:
std::vector<Memento> history;
};
int main() {
TextEditor editor;
History history;
// 设置文本并保存状态
editor.setText("Hello, World!");
history.push(editor.save());
// 修改文本并保存状态
editor.setText("Hello, Design Patterns!");
history.push(editor.save());
// 恢复到上一个状态
editor.restore(history.pop());
// 恢复到更早的状态
editor.restore(history.pop());
return 0;
}
解释
- Memento 类:存储 TextEditor 的状态(文本内容)。
- TextEditor 类 :需要保存和恢复状态的对象,提供了保存状态(
save
方法)和恢复状态(restore
方法)的功能。 - History 类:管理备忘录对象的集合,允许保存多个状态快照并按需恢复。
- main 函数:演示如何使用备忘录模式实现文本编辑器的撤销功能。
适用性和优点
-
优点:
- 保持封装性:备忘录模式将状态保存逻辑封装在 Originator 内部,避免了直接暴露对象的内部状态。
- 简化 Originator:状态保存和恢复逻辑被封装在 Memento 中,Originator 的代码更简洁。
- 支持多级撤销:通过管理多个备忘录对象,可以实现多级撤销功能。
-
缺点:
- 内存消耗:如果需要保存大量状态快照,可能会占用大量内存。
- 维护复杂性:当状态结构复杂时,备忘录对象的设计和维护可能变得复杂。
总结
备忘录模式是一种非常有用的设计模式,尤其是在需要保存和恢复对象状态的场景中。它通过封装状态保存和恢复逻辑,保持了对象的封装性,同时简化了状态管理的复杂性。通过结合 Caretaker 角色,备忘录模式还可以支持多级撤销等复杂功能。
备忘录模式(Memento Pattern)通常与其他设计模式协同使用,以增强其功能或简化实现。以下是一些常见的组合模式及其示例代码。
1. 备忘录模式与命令模式(Command Pattern)协同使用
协同场景
在需要实现撤销/重做功能时,备忘录模式可以与命令模式协同使用。命令模式用于封装操作,而备忘录模式用于保存对象的状态。
示例代码
cpp
#include <iostream>
#include <string>
#include <vector>
// Memento: 存储 Originator 的状态
class Memento {
public:
Memento(const std::string& state) : state(state) {}
std::string getState() const { return state; }
private:
std::string state;
};
// Originator: 需要保存和恢复状态的对象
class TextEditor {
public:
void setText(const std::string& text) {
this->text = text;
std::cout << "Text set to: " << text << std::endl;
}
std::string getText() const { return text; }
Memento save() const { return Memento(text); }
void restore(const Memento& memento) {
text = memento.getState();
std::cout << "Restored to text: " << text << std::endl;
}
private:
std::string text;
};
// Command: 命令接口
class Command {
public:
virtual ~Command() = default;
virtual void execute() = 0;
virtual void undo() = 0;
};
// ConcreteCommand: 具体命令
class SetTextCommand : public Command {
public:
SetTextCommand(TextEditor& editor, const std::string& newText)
: editor(editor), newText(newText), backup(editor.save()) {}
void execute() override {
editor.setText(newText);
}
void undo() override {
editor.restore(backup);
}
private:
TextEditor& editor;
std::string newText;
Memento backup;
};
// Invoker: 命令发起者
class CommandManager {
public:
void execute(Command* command) {
commandList.push_back(command);
command->execute();
}
void undo() {
if (commandList.empty()) {
std::cout << "Nothing to undo!" << std::endl;
return;
}
commandList.back()->undo();
commandList.pop_back();
}
private:
std::vector<Command*> commandList;
};
int main() {
TextEditor editor;
CommandManager commandManager;
// 设置初始文本
editor.setText("Hello");
// 执行命令:设置新文本
commandManager.execute(new SetTextCommand(editor, "Hello, World!"));
// 执行命令:再次设置新文本
commandManager.execute(new SetTextCommand(editor, "Hello, Design Patterns!"));
// 撤销命令
commandManager.undo();
commandManager.undo();
return 0;
}
解释
- Memento 类:用于保存 TextEditor 的状态。
- TextEditor 类:需要保存和恢复状态的对象。
- Command 接口:定义了命令的通用接口。
- SetTextCommand 类:具体的命令实现,封装了文本设置操作,并使用备忘录模式保存前一个状态以便撤销。
- CommandManager 类:管理命令的执行和撤销。
通过这种方式,备忘录模式与命令模式协同工作,实现了撤销功能。
2. 备忘录模式与观察者模式(Observer Pattern)协同使用
协同场景
在需要实现状态快照的实时通知时,备忘录模式可以与观察者模式协同使用。备忘录模式保存状态,而观察者模式通知其他对象状态的变化。
示例代码
cpp
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
// Memento: 存储 Originator 的状态
class Memento {
public:
Memento(const std::string& state) : state(state) {}
std::string getState() const { return state; }
private:
std::string state;
};
// Originator: 需要保存和恢复状态的对象
class TextEditor {
public:
void setText(const std::string& text) {
this->text = text;
notifyObservers();
}
std::string getText() const { return text; }
Memento save() const { return Memento(text); }
void restore(const Memento& memento) {
text = memento.getState();
notifyObservers();
}
// 观察者模式相关方法
void attach(class Observer* observer) {
observers.push_back(observer);
}
void detach(class Observer* observer) {
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
}
void notifyObservers() {
for (auto observer : observers) {
observer->update(save());
}
}
private:
std::string text;
std::vector<class Observer*> observers;
};
// Observer: 观察者接口
class Observer {
public:
virtual ~Observer() = default;
virtual void update(const Memento& memento) = 0;
};
// ConcreteObserver: 具体观察者
class History : public Observer {
public:
void update(const Memento& memento) override {
history.push_back(memento);
std::cout << "Snapshot saved: " << memento.getState() << std::endl;
}
Memento pop() {
if (history.empty()) {
throw std::runtime_error("No more mementos!");
}
Memento memento = history.back();
history.pop_back();
return memento;
}
private:
std::vector<Memento> history;
};
int main() {
TextEditor editor;
History history;
// 注册观察者
editor.attach(&history);
// 设置文本
editor.setText("Hello, World!");
editor.setText("Hello, Design Patterns!");
// 恢复状态
editor.restore(history.pop());
return 0;
}
解释
- Memento 类:用于保存 TextEditor 的状态。
- TextEditor 类:集成了备忘录模式和观察者模式。当状态更改时,通知所有观察者(如 History)。
- Observer 接口:定义观察者的通用接口。
- History 类:具体观察者,负责保存状态快照。
通过这种方式,备忘录模式与观察者模式协同工作,实现了状态变更的实时通知和快照保存。
3. 备忘录模式与迭代器模式(Iterator Pattern)协同使用
协同场景
在需要遍历历史状态时,备忘录模式可以与迭代器模式协同使用。迭代器模式用于遍历备忘录对象的集合。
示例代码
cpp
#include <iostream>
#include <vector>
#include <memory>
// Memento: 存储 Originator 的状态
class Memento {
public:
Memento(const std::string& state) : state(state) {}
std::string getState() const { return state; }
private:
std::string state;
};
// Originator: 需要保存和恢复状态的对象
class TextEditor {
public:
void setText(const std::string& text) {
this->text = text;
}
std::string getText() const { return text; }
Memento save() const { return Memento(text); }
void restore(const Memento& memento) {
text = memento.getState();
}
private:
std::string text;
};
// History: 管理 Memento 对象的集合
class History {
public:
void push(const Memento& memento) {
history.push_back(std::make_shared<Memento>(memento));
}
std::shared_ptr<Memento> pop() {
if (history.empty()) {
throw std::runtime_error("No more mementos!");
}
auto memento = history.back();
history.pop_back();
return memento;
}
class Iterator {
public:
Iterator(const std::vector<std::shared_ptr<Memento>>& history) : history(history), index(0) {}
bool hasNext() const { return index < history.size(); }
std::shared_ptr<Memento> next() {
if (!hasNext()) {
throw std::runtime_error("No more elements!");
}
return history[index++];
}
private:
const std::vector<std::shared_ptr<Memento>>& history;
size_t index;
};
Iterator createIterator() const { return Iterator(history); }
private:
std::vector<std::shared_ptr<Memento>> history;
};
int main() {
TextEditor editor;
History history;
// 保存状态
editor.setText("Hello, World!");
history.push(editor.save());
editor.setText("Hello, Design Patterns!");
history.push(editor.save());
// 遍历历史状态
History::Iterator iterator = history.createIterator();
while (iterator.hasNext()) {
std::cout << "Snapshot: " << iterator.next()->getState() << std::endl;
}
return 0;
}
解释
- History 类:管理备忘录对象的集合,并提供迭代器功能。
- Iterator 类:迭代器模式的核心,用于遍历备忘录对象的集合。
通过这种方式,备忘录模式与迭代器模式协同工作,实现了对历史状态的遍历。
总结
备忘录模式可以与其他设计模式(如命令模式、观察者模式和迭代器模式)协同使用,以增强系统的功能和灵活性。这些组合模式的应用场景包括撤销/重做、实时状态通知和历史状态遍历等。