1.备忘录模式的定义
不知道为什么这个星期要做很多事情,又好久没有学习了
备忘录模式,这个模式的名字我总觉得起的不恰当,根据现代人的理解,似乎称之为存档/读档模式更好一点,毕竟备忘录对我来说,只是临时记录一下一些很重要的事情,但是这个模式本身却是标准的存档,然后觉得不行了获取存档的功能。所以我觉得对我个人而言,称其为存档/读档模式似乎更恰当一点。
然后就是备忘录模式的官方定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后即可将该对象恢复到原先保存的状态。这个官方定义就是标准读/存档原理,很易于理解,不必细说了。
2.备忘录模式的类图
备忘录模式的类图很简单,Memento存档类为中间核心,Originator发布类与其呈依赖关系,Caretaker与其呈聚合关系,没有面向抽象类的编程过程。其中:
- Originator发布类:其存储所有表示其属性的信息State(一般情况下,这种内部属性数据会很多很多),然后有创建一个存档的函数CreateMemento,以及读取一个存档的函数SetMemento(其调用了Memento存档类的对象,故呈依赖关系)。
- Memento存档类:存档类中的数据,即为Originator发布类中的State数据。常规情况下,存档一旦存储了就不能更改,即只能读不能改。
- Caretaker管理员类:其用来管理Originator发布类所创建的存档,实现存档的增删读等操作。由于存档通常为多个,故其内部必然有存储这些存档的容器(故与Memento存档类呈聚合关系)。
3.备忘录模式的代码实现
说到存档和读档,那想到的必然是游戏,本例中以著名波兰游戏TheWitcher3为Originator发布类(RPGgame),其底层系统TheWitcher3_System为Caretaker管理员类(RPGgame_System),其内部的存档为Memento类(SaveFile),根据上述类图实现了存档与读档的功能。
本例实现的基本功能与标准类图基本一致,在此不做赘述,值得一提的是,本例中的存档名字采用当前系统 时间来判断,其中使用了windows.h文件。
#include <iostream>
#include <string>
#include <map>
#include <windows.h>
using namespace std;
string GetSystemTime() //获取当前系统时间
{
SYSTEMTIME m_time;
GetLocalTime(&m_time);
char szDateTime[100] = { 0 };
sprintf_s(szDateTime, "%02d-%02d-%02d %02d:%02d:%02d", m_time.wYear, m_time.wMonth,
m_time.wDay, m_time.wHour, m_time.wMinute, m_time.wSecond);
string time(szDateTime);
return time;
}
class SaveFile
{
public:
SaveFile(int level, string mission, map<string, int> package, string savefilname)
{
sf_level = level;
sf_mission = mission;
sf_package = package;
sf_savefilname = savefilname;
}
void ChangeSaveFile(int level, string mission, map<string, int> package)
{
sf_level = level;
sf_mission = mission;
sf_package = package;
}
string getName()
{
return sf_savefilname;
}
map<string, int> getpackage()
{
return sf_package;
}
string getmission()
{
return sf_mission;
}
int getlevel()
{
return sf_level;
}
private:
int sf_level;
string sf_mission;
map<string, int> sf_package;
string sf_savefilname;
};
class RPGgame
{
public:
RPGgame(int level, string mission, map<string, int> package)
{
m_level = level;
m_mission = mission;
m_package = package;
}
SaveFile* CreateSaveFile()
{
return new SaveFile(m_level, m_mission, m_package, GetSystemTime());
}
void ChangeGame(int level, string mission, map<string, int> package)
{
m_level = level;
m_mission = mission;
m_package = package;
}
void LoadSaveFile(SaveFile* savefile)
{
m_level = savefile->getlevel();
m_mission = savefile->getmission();
m_package = savefile->getpackage();
}
void DisplaySaveFile()
{
cout << "m_level is " << m_level << endl;
cout << "m_mission is " << m_mission << endl;
for (auto &s : m_package)
cout << s.first << " have " << s.second << endl;
}
private:
int m_level;
string m_mission;
map<string, int> m_package;
};
class RPGgameSystem
{
public:
void InsertSaveFile(SaveFile* savefile)
{
m_savefile.insert({ savefile->getName(),savefile });
}
SaveFile* useSaveFile(string name)
{
return m_savefile.at(name);
}
void RemoveaveFile(string name)
{
m_savefile.erase(name);
}
private:
map<string, SaveFile*> m_savefile;
};
int main()
{
RPGgameSystem* TheWitcher3_System = new RPGgameSystem;
//用户数据的自定义
map<string, int> Geralt_Package;
Geralt_Package.insert({ "Memory Rose",1 });
Geralt_Package.insert({ "Crystal Skulls",1 });
//进入游戏读取默认存档
RPGgame* TheWitcher3 = new RPGgame(10, "Kill Monster", Geralt_Package);
//第一次存档
cout << "***** TheWitcher3第一次存档 *****" << endl;
SaveFile* savefile1 = TheWitcher3->CreateSaveFile();
TheWitcher3_System->InsertSaveFile(savefile1);
TheWitcher3->DisplaySaveFile();
//第二次存档
Sleep(1000);
cout << "***** TheWitcher3第二次存档 *****" << endl;
TheWitcher3->ChangeGame(12, "Find Child", Geralt_Package);
SaveFile* savefile2 = TheWitcher3->CreateSaveFile();
TheWitcher3_System->InsertSaveFile(savefile2);
TheWitcher3->DisplaySaveFile();
//第一次读档
cout << "***** TheWitcher3第一次读档 *****" << endl;
TheWitcher3->LoadSaveFile(TheWitcher3_System->useSaveFile(savefile1->getName()));
TheWitcher3->DisplaySaveFile();
//第二次读档
cout << "***** TheWitcher3第二次读档 *****" << endl;
TheWitcher3->LoadSaveFile(TheWitcher3_System->useSaveFile(savefile2->getName()));
TheWitcher3->DisplaySaveFile();
delete TheWitcher3_System;
delete TheWitcher3;
delete savefile1;
delete savefile2;
return 0;
}