#include <iostream> #include <vector>#ifdef _DEBUG //只在Debug(调试)模式下 #ifndef DEBUG_NEW #define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__) //重新定义new运算符 #define new DEBUG_NEW #endif #endif//#include <boost/type_index.hpp> using namespace std; //#pragma warning(disable : 4996) namespace _nmsp1 { //玩家主角相关的备忘录类class FighterMemento{private://构造函数,用private修饰以防止在外部被随意创建FighterMemento(int life,int magic,int attack):m_life(life), m_magic(magic), m_attack(attack) {}private://提供一些供Fighter类访问的接口,用private修饰防止被任意类访问friend class Fighter; //友元类Fighter可以访问奔雷的私有成员函数int getLife() const { return m_life; }void setLife(int life) { m_life = life; }int getMagic() const { return m_magic; }void setMagic(int magic) { m_magic = magic; }int geAttack() const { return m_attack; }void setAttack(int attack) { m_attack = attack; }private://玩家主角类中要保存起来的数据,就放到这里来int m_life; //生命值int m_magic; //魔法值int m_attack; //攻击力 };//玩家主角类class Fighter{public://构造函数Fighter(int life, int magic, int attack) :m_life(life), m_magic(magic), m_attack(attack) {}public://将玩家数据写入备忘录(创建备忘录,并在其中存储了当前状态)FighterMemento* createMomento(){return new FighterMemento(m_life, m_magic, m_attack);}//从备忘录中恢复玩家数据void restoreMomento(FighterMemento* pfm){m_life = pfm->getLife();m_magic = pfm->getMagic();m_attack = pfm->geAttack();}//为测试目的引入的接口,设置玩家的生命值为0(玩家死亡)void setToDead(){m_life = 0;}//用于输出一些信息void displayInfo(){cout << "玩家主角当前的生命值、魔法值、攻击力分别为:" << m_life << "," << m_magic << "," << m_attack << endl;}private://角色属性int m_life; //生命值int m_magic; //魔法值int m_attack; //攻击力//.....其他数据略 };//管理者(负责人)类class FCareTaker{public://构造函数FCareTaker(FighterMemento* ptmpfm) :m_pfm(ptmpfm) {} //形参是指向备忘录对象的指针//获取指向备忘录对象的指针FighterMemento* getMemento(){return m_pfm;}//保存指向备忘录对象的指针void setMemento(FighterMemento *ptmpfm){m_pfm = ptmpfm;}private:FighterMemento* m_pfm; //指向备忘录对象的指针 };//------------------------//支持多个快照的负责人(管理者)类class FCareTaker2{public://析构函数用于释放资源~FCareTaker2(){for (auto iter = m_pfmContainer.begin(); iter != m_pfmContainer.end(); ++iter){delete (*iter);}}//保存指向备忘录对象的指针void setMemento(FighterMemento* ptmpfm){m_pfmContainer.push_back(ptmpfm);}//获取指向备忘录对象的指针FighterMemento* getMemento(int index){auto iter = m_pfmContainer.begin();for (int i = 0; i <= index; ++i){if (i == index)return (*iter);else++iter;}return NULL;}private://存储备忘录对象指针的容器vector<FighterMemento*> m_pfmContainer; };}int main() {_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口/*_nmsp1::Fighter* p_fighter = new _nmsp1::Fighter(800, 200, 300);//(1)显示玩家主角在与BOSS战斗之前的信息p_fighter->displayInfo();//(2)为玩家主角类对象创建一个备忘录(其中保存了当前主角类对象中的必要信息)//_nmsp1::FighterMemento* p_fighterMemo = p_fighter->createMomento();_nmsp1::FCareTaker* pfcaretaker = new _nmsp1::FCareTaker(p_fighter->createMomento());//(3)玩家与BOSS开始战斗cout << "玩家主角与BOSS开始进行激烈的战斗-------" << endl;p_fighter->setToDead(); //玩家主角在与BOSS战斗中,生命值最终变成0而死亡(被BOSS击败)p_fighter->displayInfo(); //显示玩家主角在与BOSS战斗之后的信息//(4)因为在与BOSS战斗之前已经通过NPC保存了游戏进度,这里模拟载入游戏进度,恢复玩家主角类对象的数据,让其可以与BOSS再次战斗cout << "玩家主角通过备忘录恢复自己的信息------" << endl;//p_fighter->restoreMomento(p_fighterMemo);p_fighter->restoreMomento(pfcaretaker->getMemento());p_fighter->displayInfo(); //显示玩家主角通过备忘录恢复到战斗之前的信息//(5)释放资源//delete p_fighterMemo;delete pfcaretaker->getMemento();delete pfcaretaker; delete p_fighter;*/_nmsp1::Fighter* p_fighter2 = new _nmsp1::Fighter(800, 200, 300);_nmsp1::FCareTaker2* pfcaretaker2 = new _nmsp1::FCareTaker2();pfcaretaker2->setMemento(p_fighter2->createMomento()); //做第一次快照,此快照玩家生命值为800。p_fighter2->setToDead(); //改变玩家主角的生命值pfcaretaker2->setMemento(p_fighter2->createMomento());//做第二次快照,此快照玩家生命值为0。p_fighter2->displayInfo(); //玩家主角生命值应为为0.cout << "----------------" << endl;//当前玩家生命值为0,恢复第一次快照,也就是恢复玩家生命值为800p_fighter2->restoreMomento(pfcaretaker2->getMemento(0));p_fighter2->displayInfo(); //玩家生命值应该恢复为800//释放资源delete p_fighter2;delete pfcaretaker2;return 0; }
备忘录(Memento)模式:快照模式(Snapshot),行为型模式。
//(1)一个具体实现范例
// 一般该模式还会引入一个 管理者(负责人)类,但是这并不是必须的。 FCareTaker
//(2)引入备忘录(Memento)模式
//定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,
//这样以后就可以将该对象恢复到原先保存的状态
//3种角色
//a)Originator(原发器):Fighter类。
//b)Memento(备忘录):FighterMemnto类。
//c)CareTaker(负责人/管理者):FCareTaker类。
//备忘录真正的作用并不是保存数据,而是恢复数据。
//说明:
//a)快照——并不意味着所有玩家主角类的信息都要往备忘录中保存。
//b)做快照并不要求玩家主角类中需要保存的字段都一一对应备忘录中相同的字段,备忘录中可以以
//内存流,字符串,编码(Hex编码、Base64编码)方式存储或者还原来自玩家主角类中的数据。
//数据序列化。
//c)给玩家主角类做快照并不仅仅限于一次。FCareTaker2做多次快照。给了一个范例
//d)friend
//e)更适合保存原发器对象中的一部分(不是所有)内部状态,否则采用原型模式。
//f)优点:方便回到一个特定的历史步骤。缺点:对资源的消耗。
//g)完全存储。增量存储来应付频繁做快照。 完全存储和增量存储方式结合使用。Redis,RDB(完全备份),AOF(增量备份)。
//减少需要记录的数据。
//h)应用场合:下棋悔棋,保存历史记录,做快照。
//i)数据保存在内存中以及从内存中恢复数据。