备忘录模式是一种行为型设计模式,顾名思义就是起到备忘的功能。我们常见文本编辑器都有“撤销”的功能,一般对应的键盘映射是Ctrl+z
,且可以多次使用返回上上次的历史情况。
那么,实现这种功能的设计模式就是备忘录模式。
基本结构
我们了解了备忘录的实际含义,就来说一下其中存在的几种角色
- 发起人
Originator
:需要还原状态的那个对象,负责创建一个【备忘录】,并使用备忘录记录当前时刻的内部状态。 - 备忘录
Memento
:存储发起人对象的内部状态,他可以包含发起人的部分护着全部状态信息,但是对于外部是不可见的,只有发起人能够访问备忘录对象的状态。 - 管理者
Caretaker
:负责存储备忘录对象,但并不了解其内部结构,管理者可以存储多个备忘录对象(栈)。 - 客户端:在需要恢复状态时,客户端可以从管理者那里获取备忘录对象,并将其传给发起人进行状态的恢复。
uml类中,发起人依赖备忘录实现“备忘”,管理者相当于多个备忘录的聚合关系,而客户端宏观上使用备忘录模式。
代码举例
#include<bits/stdc++.h>
using namespace std;
// 备忘录
class Memento {
public:
virtual ~Memento() {}
virtual string GetName() const = 0;
virtual string date() const = 0;
virtual string state() const = 0;
};
// 具体备忘录
class ConcreteMemento :public Memento {
private:
string state_;
string date_;
public:
ConcreteMemento(string state) :state_(state) {
this->state_ = state; // 记录状态
time_t now = time(0);
this->date_ = ctime(&now); // 记录具体的时间
}
string state() const override {
return this->state_;
}
string GetName() const override {
return this->date_ + "/ (" + this->state_.substr(0, 9) + "...)";
}
string date() const override {
return this->date_;
}
};
// 发起者
class Originator {
private:
string state_;
string GenerateRandomString(int len = 10) {
const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
int stringlen = sizeof(alphanum) - 1;
string random_string;
for (int i = 0; i < len; i++) {// 生成随机字符串
random_string += alphanum[rand() % stringlen];
}
return random_string;
}
public:
Originator(string state) :state_(state) {
cout << "Orignator: My initial state is " << this->state_ << endl;
}
void DoSomething() {
cout << "Orignator: I'm doing something important.\n";
this->state_ = this->GenerateRandomString(30);
cout << "Orignator: and my state has changed to " << this->state_ << endl;
}
Memento* Save() {
return new ConcreteMemento(this->state_); // 保存当前状态
}
void Restore(Memento* memento) { // 恢复之前的状态, 传入备忘录
this->state_ = memento->state();
cout << "Originator: My state has changed to: " << this->state_ << endl;
}
};
class Caretaker {
private:
vector<Memento*> mementolist;// 备忘录列表,使用数组模拟栈
Originator* orignator_;
public:
Caretaker(Originator* orignator) :orignator_(orignator) {}
~Caretaker() { for (auto m : mementolist) delete m; }
void Backup() {
cout << "\nCaretaker: Saving Originator's state:...\n";
this->mementolist.push_back(this->orignator_->Save());
}
void Undo() {
if (this->mementolist.empty()) {
return;
}
Memento* mem = this->mementolist.back();
this->mementolist.pop_back();
cout << "Caretaker: Restoring state to: " << mem->GetName() << endl;
try {
this->orignator_->Restore(mem);
}
catch (...) {
this->Undo(); // 出现异常就回滚
}
}
void ShowHistory() {
cout << "Caretaker: Here's the list of mementos:\n";
for (auto& it : this->mementolist) {
cout << it->GetName() << endl;
}
}
};
// 定义客户端函数
void ClientCode() {
// 创建发起者
Originator* ori = new Originator("Super-duper-super-puper-super.");
// 创建管理者
Caretaker* care = new Caretaker(ori);
care->Backup();// 备份当前状态
ori->DoSomething();
care->Backup();
ori->DoSomething();
care->Backup();
ori->DoSomething();
cout << endl;
care->ShowHistory();
cout << "\nClient: Now, let's roolback!\n";
care->Undo();
cout << "\nClien: Once more\n";
care->Undo();
delete ori, care;
}
int main() {
//设置随机种子
srand(static_cast<unsigned int> (time(NULL)));
// 调用客户端
ClientCode();
return 0;
}
输出:
Orignator: My initial state is Super-duper-super-puper-super.
Caretaker: Saving Originator's state:...
Orignator: I'm doing something important.
Orignator: and my state has changed to cWTYThunPtuGSdepH2S3jFPHZlUGIZ
Caretaker: Saving Originator's state:...
Orignator: I'm doing something important.
Orignator: and my state has changed to K6L7mOV7XkLrxbVBoWn7H1BoeO5Qg6
Caretaker: Saving Originator's state:...
Orignator: I'm doing something important.
Orignator: and my state has changed to 9O6w7UfIPpPuZx14x15BWlqR0q6aGv
Caretaker: Here's the list of mementos:
Sun Nov 3 23:46:14 2024
/ (Super-dup...)
Sun Nov 3 23:46:14 2024
/ (cWTYThunP...)
Sun Nov 3 23:46:14 2024
/ (K6L7mOV7X...)
Client: Now, let's roolback!
Caretaker: Restoring state to: Sun Nov 3 23:46:14 2024
/ (K6L7mOV7X...)
Originator: My state has changed to: K6L7mOV7XkLrxbVBoWn7H1BoeO5Qg6
Clien: Once more
Caretaker: Restoring state to: Sun Nov 3 23:46:14 2024
/ (cWTYThunP...)
Originator: My state has changed to: cWTYThunPtuGSdepH2S3jFPHZlUGIZ
上述代码稍显冗长,不过仔细看完,核心在于客户端每次通过caretaker
的提前备份(Backup),originator
发起人再修改(DoSomething),之后再Undo就可以将vector的末尾弹出替换当前状态,相当于“撤回”功能,这里vector模拟的就是一个栈。
总结一下
备忘录模式将创建状态快照 (Snapshot) 的工作委派给实际状态的拥有者原发器(Originator) 对象。 这样其他对象就不再需要从 “外部” 复制编辑器状态了, 编辑器类拥有其状态的完全访问权, 因此可以自行生成快照。即原发器拥有对备忘录的完全访问权限, 负责人则只能访问元数据。
这种限制策略允许你将备忘录保存在通常被称为_负责人_ (Caretakers) 的对象中。 由于负责人仅通过受限接口与备忘录互动, 故其无法修改存储在备忘录内部的状态。 同时, 原发器拥有对备忘录所有成员的访问权限, 从而能随时恢复其以前的状态。
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » 设计模式——备忘录模式
发表评论 取消回复