一、概述
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
二、结构
- 备忘录角色(Memento): 负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人;
- 发起人角色(Originator): 记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,可以根据需要决定备忘录角色中保存自身的哪些内部状态,能够访问备忘录里的所有信息;
- 管理者角色(Caretaker): 对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改,只能够将备忘录传递给其他对象。
三、实例
#include<iostream>
#include<map>
using namespace std;
/*
/需要保存的信息
此处将需要保存的信息提取出来放在一个结构体中
也可以不用放在结构体中,直接作为类的成员变量
*/
typedef struct
{
int nHp;//血量
int nMp;//蓝量
int nAttack;//攻击
} GameValue;
//备忘录类:存储发起人的内部状态
class Memento {
private:
GameValue m_gameValue;
public:
Memento(const GameValue &gameValue):m_gameValue(gameValue){}
/*
前const:返回的变量不可修改
后const:该函数readonly,表示该类的this指针为const类型,不能改变类的成员变量的值
*/
//获取结构体中三个值
const GameValue& getValue()const {
return m_gameValue;
}
};
// 管理者角色:保存和获取备忘录功能
class Caretaker {
private:
//定义Memento变量,为了方便获取 Memento中的数据
map<string, shared_ptr<Memento>> mData;
public:
/*
1.GetState不是Memento的成员函数
2.此函数只能通过Caretaker的对象访问
3.此函数为了获取key值,看为了方便调用
*/
const shared_ptr<Memento>GetState(const string& key) {
return mData[key];
}
void SetState(const string& key,
shared_ptr<Memento> pMemento) {
mData[key] = pMemento;
}
};
//发起人角色
class Hero {
private:
GameValue m_gameValue;
//定义Caretaker变量,方便调用Caretaker函数
Caretaker m_Caretaker;
public:
Hero():m_gameValue{100,100,100}{}
Hero(const GameValue& gameValue):m_gameValue(gameValue){}
//保存当前信息
void saveState(const string& key)
{
m_Caretaker.SetState(key, make_shared<Memento>(m_gameValue));
}
//恢复信息
const void resumState(const string& key) {
m_gameValue = m_Caretaker.GetState(key)->getValue();
}
void battle()
{
m_gameValue.nHp = rand() % 100;
m_gameValue.nMp = rand() % 100;
m_gameValue.nAttack = rand() % 100;
}
void showState() {
cout << "血量:" << m_gameValue.nHp << endl
<< "蓝量:" << m_gameValue.nMp << endl
<< "攻击:" << m_gameValue.nAttack << endl;
}
};
int main()
{
Hero hero;
cout << "战斗前" << endl;
hero.showState();
cout << endl;
hero.saveState("战斗前");
hero.battle();
cout << "战斗1后" << endl;
hero.showState();
cout << endl;
hero.saveState("战斗1后");
hero.battle();
cout << "战斗2后" << endl;
hero.showState();
cout << endl;
hero.saveState("战斗2后");
cout << endl;
hero.resumState("战斗1后");
cout << "恢复战斗1的结果" << endl;
hero.showState();
cout << endl;
hero.resumState("战斗2后");
cout << "恢复战斗2的结果" << endl;
hero.showState();
cout << endl;
hero.resumState("战斗前");
cout << "恢复战斗前" << endl;
hero.showState();
cout << endl;
return 0;
}
四、优缺点
优点:
- 实现了信息的封装,使得用户不需要关心状态的保存细节。
- 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态;
缺点:
- 消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。
- 必须完整跟踪原发器的生命周期,这样才能销毁弃用的备忘录。
五、应用场景
- 需要保存/恢复数据的相关状态场景。
- 直接访问对象的成员变量、获取器或设置器将导致封装被突破时,可以使用该模式。
六、对比
备忘录模式与原型模式:
- 原型模式保存的是当前对象的所有状态信息,恢复的时候会生成与保存的对象完全相同的另外一个实例;
- 备忘录模式保存的是我们关心的在恢复时需要的对象的部分状态信息,相当于快照。