目录
基本概念:
动机:
在软件构建过程中某些对象的状态在转换过程中由于某种需要要求程序可以回溯到之前对象某个所处的状态;如文档编辑器的撤销动作、游戏的存档等。
定义:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便于在不同时机可以切换到不同的状态中。
代码举例:
备忘录状态类:
描述元发器所有可能变化的状态的类,这里以string字符串记录(实际中对象常可很方便的序列化)。
//备忘录状态类
class Memento
{
string state;
//..
public:
Memento(const string & s) : state(s) {}
string getState() const { return state; }
void setState(const string & s) { state = s; }
};
元发起类:
业务类,会有状态变化,在需要记录当前状态时可以Memento*createMemento()创建当前状态供备忘录管理类记录,在需要恢复某一状态时可以通过restoreMemento(Memento*m)恢复状态m。
//业务中 元发器
class Originator
{
string state;
//....
public:
Originator() {}
~Originator(){}
//业务相关函数 会修改当前状态state
/*
...
*/
//创建备忘录记录
Memento* createMemento() {
return new Memento(state);
}
//恢复备忘录
void restoreMemento(Memento*m)
{
state = m->getState();
}
};
备忘录管理类:
记录元发器创建的状态,在元发器业务需要恢复某一状态时提供状态便于其恢复。
class MemManager
{
public:
MemManager() {};
~MemManager() {
for (auto iter = m_MementoVec.begin(); iter != m_MementoVec.end(); iter++)
{
delete (*iter);
}
}
void setMomento(Memento* m) {
m_MementoVec.push_back(m);
}
Memento* getMemento(int index)
{
return m_MementoVec.at(index);
}
Memento* getLastMemento()
{
return m_MementoVec.at(m_MementoVec.size() - 1);
}
private:
vector<Memento*>m_MementoVec;
};
调用示例:
int main()
{
Originator orginator;
MemManager memManger;
//捕获对象状态,存储到备忘录
memManger.setMomento(orginator.createMemento());
//... 改变orginator状态
memManger.setMomento(orginator.createMemento());
//... 改变orginator状态
//从备忘录中恢复最初状态
orginator.restoreMemento(memManger.getMemento(0));
//恢复最近一次备忘录 撤销操作
orginator.restoreMemento(memManger.getLastMemento());
}
停车场项目中使用
问题背景
在停车项目中有许多场景共用一个界面,但是在不同状态下需要切换显示不通的参数配置,如多个车道可以共用一个车道配置界面,各个车道的配置因为进出口、收费与否、音量大小、过车规则等等配置各异,但是车道的配置界面一样可共用。此时使用备忘录模式进行优化设计,当车道切换时记录当前车道的状态(配置参数),同时还原切到的车道的状态(配置参数);这样就可以在一个配置界面上配置显示多个车道配置信息。
代码举例
车道备忘录状态类:
目前项目中大部分类通过Qt的反射,自定义实现了json的序列化和反序列化,因此车道状态用字符串记录,方便存储与检验变更等。
//备忘录状态类
class MemLaneCfg
{
string laneCfgStr;
//..
public:
MemLaneCfg(const string & s) : laneCfgStr(s) {}
string getLaneCfg() const { return laneCfgStr; }
void setLaneCfg(const string & s) { laneCfgStr = s; }
};
车道备忘录管理类
#define g_LaneCfgMemHelper Singleton<LaneCfgMemManager>::getInstance()
class LaneCfgMemManager
{
friend Singleton<LaneCfgMemManager>;
public:
void setLaneCfgMomento(const string&laneCodeStr, std::shared_ptr<MemLaneCfg> memCfg) {
m_laneCode2Mem[laneCodeStr] = memCfg;
}
std::shared_ptr<MemLaneCfg> getLaneCfgByLaneCode(const string&laneCodeStr)
{
if (m_laneCode2Mem.find(laneCodeStr)!= m_laneCode2Mem.end())
{
return m_laneCode2Mem.at(laneCodeStr);
}
return nullptr;
}
private:
unordered_map<string,std::shared_ptr<MemLaneCfg>>m_laneCode2Mem;
LaneCfgMemManager() {};
~LaneCfgMemManager() {
}
};
车道配置类:
该类在车道保存时会触发当前车道配置备忘录的存储,在车道切换时会触发切换后车道配置备忘录的刷新。
class QLaneConfig : public QFrame
{
Q_OBJECT
public:
QLaneConfig(QWidget *parent = Q_NULLPTR);
~QLaneConfig();
/*
...
*/
private:
//创建当前车道的备忘录
std::shared_ptr<MemLaneCfg>createMemento() {
ScreenConfig::LaneDisplayDto laneDtoDate;
/*
根据界面配置信息填充laneDtoDate
...
*/
string laneCfgStr = laneDtoDate.toJson();//序列化
return std::make_shared<MemLaneCfg>(new MemLaneCfg(laneCfgStr));
}
//恢复指定车道备忘录
void restoreMemento(const string laneCodeStr)
{
auto laneCfgMemPtr = g_LaneCfgMemHelper->getLaneCfgByLaneCode(laneCodeStr);
string laneCfgStr = laneCfgMemPtr->getLaneCfg();
ScreenConfig::LaneDisplayDto laneDtoDate;
if (0 == dtoLane.ConvertBy(laneCfgStr))//反序列化得到车道对象
{
//配置刷新车道界面各个参数
}
}
/*
...
*/
private slots:
//切换车道槽函数
void switchLaneSlots(const string&laneCodeStr)
{
restoreMemento(laneCodeStr);
}
//保存当前配置信息
void on_btnApply_clicked()
{
auto cfgMemPtr = createMemento();
g_LaneCfgMemHelper->setLaneCfgMomento(m_laneCodeStr, cfgMemPtr);
//数据库存储当前车道配置
//...
}
private:
bool aboutToSave(bool onlyCheck, string &strErrorMsg); // 缓存界面配置信息
/*
...
*/
};