1. 备忘录模式(Memento Pattern)的定义
(1)定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
①不破坏封装性:对象不能暴露它不应该暴露的细节。
②捕获对象的内部状态:保存状态的目的是为了恢复,把以将某个对象的状态保存在备忘录对象中,以便以后的恢复。
③对象的内部状态保存在备忘录对象中,而备忘录对象通常被存储在原发器对象之外,一般保存在管理者对象那里。
(2)备忘录模式的结构和说明
①Originator:原发器。使用备忘录来保存某个时刻原发器自身的状态,也可以使用备忘录来恢复这些内部状态。
②备忘录:主要用来存储原发器对象的内部状态,但是具体需要存储哪些数据是由原发器对象来决定的。另外备忘录应该只能由原发器对象来访问它的内部数据,原发器外部的对象不应该访问到备忘录对象的内部数据。
③Caretaker:备忘录的管理者。主要负责保存备忘录对象,但是不能对备忘录对象的内部进行操作或检查。
(3)备忘录模式的本质:保存和恢复内部状态
2. 深入理解备忘录模式
(1)备忘录对象
①通常就是用来记录原发器对象需要保存的状态信息。
②备忘录对象是用来封装数据的,但与普通的封装数据的对象不同,备忘录对象一般只让原发器对象操作。为了保存这一点,通常会把备忘录对象作为原发器对象的内部类来实现,而且实现成私有的,然后通常一个窄接口来标识对象的类型,以便以外部交互。
(2)原发器对象
①需要被保存状态的对象,该对象应该提供捕获某个时刻对象内部状态的方法,在这个方法中,原发器对象会创建备忘录对象,把需要保存的状态数据设置到备忘录对象中,然后把备忘录对象提供给管理者对象来保存。
②当然,原发器对象也提供了利用备忘录对象来恢复内部状态的方法。
(3)管理者对象:主要负责保存备忘录对象
①并不一定需要一个管理者对象。广义来说,调用原发器获得备忘录对象后,备忘录放在哪里,那个对象就是管理者对象。
②管理者对象并不是只管理一个备忘录对象,它可以管理多个备忘录对象。
③狭义的管理者只管理同一类的备忘录对象,但广义的管理者可以管理不同类型的备忘录对象。
④管理者对象需要实现的基本功能是:存入备忘录对象和从中获取备忘录对象。从功能上看,就是一个缓存功能或一个简单的对象实例池。
⑤管理者虽然能存取备忘录对象,但是不能访问备忘录对象的内部数据。
(4)宽接口和窄接口
①在实现Memento模式中,要防止原发器以外的对象访问备记录对象,备忘录对象有两个接口,一个为原发器使用的宽接口,一个为其他对象使用的窄接口。
②窄接口:管理者只能看到备忘录的窄接口,这个接口的实现通常没有任何的方法,只是一个类型标识。窄接口使得管理者只能将备忘录传递给其他对象
③宽接口:原发器能够看到一个宽接口,允许它访问所需的所有数据,来返回先前的状态。通常实现成为原发器内的一个私有内部类。
(5)使用备忘录模式的潜在代价
在实现Memento模式是,要考虑拷贝对象状态的效率问题,如果对象开销比较大,可以采用某个增量式改变来改进Memento模式。
(6)增量存储
如果需要频繁地创建备忘录对象,而且创建和应用备忘录对象来恢复状态的顺序是可控的,那就可以使用增量存储,也就是备忘录仅仅存储原发器内部相对于上一次存储状态后的增量改变。
【编程实验】游戏进度的保存
//声明文件
//行为型模式——备忘录模式
//场景:游戏进度的备份
#include <iostream>
#include <vector>
using namespace std;
//Memento抽象类
class CAbsMemento{
public:
virtual ~CAbsMemento();
};
//Originator:游戏角色
class CGameRole{
private:
int iVitality;//生命力
int iAttack;//攻击力
int iDefense;//防御力
//内部类,用于保存和恢复游戏进度
//备忘录对象类
class CStateMemento : public CAbsMemento{
private:
int iVit;
int iAtk;
int iDef;
public:
CStateMemento(CGameRole* role);
~CStateMemento();
int GetVitality();
int GetAttack();
int GetDefense();
};
public:
void SetVitality(int vitality);
int GetVitality();
void SetAttack(int attack);
int GetAttack();
void SetDefense(int defense);
int GetDefense();
void Disp();
//获取初始状态(数据通常来自本机或远程数据库)
void AtFirst();
//战斗(与Boss大战后,游戏数据的损耗)
void FightWithBoss1();
void FightWithBoss2();
//保存备份
CAbsMemento* SaveState();
//恢复备份
void RecoveryState(CAbsMemento* memento);
};
//实现文件
//Memento抽象类
CAbsMemento::~CAbsMemento(){ cout << "~CAbsMemento" << endl; }
//Originator:游戏角色
//备忘录对象类
CGameRole::CStateMemento::CStateMemento(CGameRole* role){
iVit = role->GetVitality(); iAtk = role->GetAttack(); iDef = role->GetDefense();
}
CGameRole::CStateMemento::~CStateMemento(){ cout << "~CStateMemento" << " Vit : " << iVit << ", iAtk : " << iAtk << ", iDef : " << iDef << endl; }
int CGameRole::CStateMemento::GetVitality(){return iVit;}
int CGameRole::CStateMemento::GetAttack(){return iAtk;}
int CGameRole::CStateMemento::GetDefense(){return iDef;}
void CGameRole::SetVitality(int vitality){iVitality = vitality;}
int CGameRole::GetVitality(){return iVitality;}
void CGameRole::SetAttack(int attack){iAttack = attack;}
int CGameRole::GetAttack(){return iAttack;}
void CGameRole::SetDefense(int defense){iDefense = defense;}
int CGameRole::GetDefense(){return iDefense;}
void CGameRole::Disp(){ //状态显示
cout << "角色当前状态:" << endl;
cout << "生命力:" << iVitality << endl;
cout << "攻击力:" << iAttack << endl;
cout << "防御力:" << iDefense << endl;
}
//获取初始状态(数据通常来自本机或远程数据库)
void CGameRole::AtFirst(){ iVitality = 100; iAttack = 100; iDefense = 100; }
//战斗(与Boss大战后,游戏数据的损耗)
void CGameRole::FightWithBoss1(){iVitality = 80; iAttack = 80; iDefense = 80;}
void CGameRole::FightWithBoss2(){iVitality = 60; iAttack = 60; iDefense = 60;}
//保存备份
CAbsMemento* CGameRole::SaveState(){return new CStateMemento(this);}
//恢复备份
void CGameRole::RecoveryState(CAbsMemento* memento){
CStateMemento* pMemento = dynamic_cast<CStateMemento*>(memento);
if(pMemento != NULL){
iVitality = pMemento->GetVitality();
iAttack = pMemento->GetAttack();
iDefense = pMemento->GetDefense();
}
}
//测试客户端
void main()
{
vector<CAbsMemento*> vGameDat;
vector<CAbsMemento*> vBackup;
CGameRole* pRole = new CGameRole();
cout << "与BOSS决战之前:" << endl;
pRole->AtFirst(); pRole->Disp();
CAbsMemento* pMemento = pRole->SaveState();
vGameDat.push_back(pMemento); vBackup.push_back(pMemento);
cout << "**********************************************" << endl;
cout << "首次与BOSS决战之后:" << endl;
pRole->FightWithBoss1(); pRole->Disp();
pMemento = pRole->SaveState();
vGameDat.push_back(pMemento); vBackup.push_back(pMemento);
cout << "再次与BOSS决战之后:" << endl;
pRole->FightWithBoss2(); pRole->Disp();
pMemento = pRole->SaveState();
vGameDat.push_back(pMemento); vBackup.push_back(pMemento);
vGameDat.pop_back();//从状态备忘录集合中删除当前状态
cout << "**********************************************" << endl;
cout << "恢复到二战前的状态:" << endl;
pMemento = vGameDat.back(); vGameDat.pop_back(); pRole->RecoveryState(pMemento); pRole->Disp();
cout << "恢复到一战前的状态:" << endl;
pMemento = vGameDat.back(); vGameDat.pop_back(); pRole->RecoveryState(pMemento); pRole->Disp();
cout << "Before deleting.. size : " << vBackup.size() << endl;
for(vector<CAbsMemento*>::iterator it = vBackup.begin(); it != vBackup.end(); ){
pMemento = (*it);
if(pMemento != NULL) delete pMemento;
it = vBackup.erase(it);
}
cout << "After deleted... size : " << vBackup.size() << endl;
}