备忘录模式(Memento Pattern)
定义
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先的状态
- originator这个类是需要被保存状态的类;
- Memento该类的对象由originator创建,主要用来保存originator的内部状态。
- Careataker负责在需要的情况下去保存或者恢复originator的状态。
常用场景
- 必须保存一个对象在某一时刻的状态,这样可以以后在需要的时候,恢复到当前状态;
- 如果让其他对象直接保存当前对象的状态,将会暴露对象的实现细节,破坏对象的封装。
优缺点
优点:
- 当发起人角色的状态有改变时,有可能是个错误的改变,我们使用备忘录模式就可以把这个错误改变还原。
- 备份的状态是保存在发起人角色之外的,这样,发起人角色就不需要对各个备份的状态进行管理
缺点:
如果备份的对象存在大量的信息或者创建、恢复操作非常频繁,则可能造成很大的性能开销
C++实现
举例:游戏存档
大家都有过玩存档类(三国、世界足球等)的游戏,我们可以将某个游戏进度存档,然后在之后可以选择加载某个游戏状态,也可以恢复到最初始状态重新玩。
类图:
代码:
/*!
*@file Memento.h
*@brief 备忘录模式
*/
#ifndef MEMENTO_H
#define MEMENTO_H
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include <utility>
// 内部状态类
class Memento
{
public:
Memento(unsigned int vitality, unsigned int attack, unsigned int defense)
: m_vitality(vitality), m_attack(attack), m_defense(defense)
{
}
~Memento() {}
void SetVitality(unsigned int vitality) {m_vitality = vitality;}
void SetAttack(unsigned int attack) {m_attack = attack;}
void SetDefense(unsigned int defense) {m_defense = defense;}
unsigned int GetVitality() {return m_vitality;}
unsigned int GetAttack() {return m_attack;}
unsigned int GetDefense() {return m_defense;}
private:
unsigned int m_vitality; // 生命值
unsigned int m_attack; // 攻击力
unsigned int m_defense; // 防御力
};
// 游戏角色
class GameRole
{
public:
GameRole() : m_vitality(100), m_attack(100), m_defense(100) {}
~GameRole() {}
void Attack()
{
m_vitality = m_vitality > 8 ? m_vitality - 8 : 0;
m_attack = m_attack > 10 ? m_attack - 10 : 0;
m_defense = m_defense > 6 ? m_defense - 6 : 0;
}
void Resume()
{
m_vitality = m_vitality < 95 ? m_vitality + 5 : 100;
m_attack = m_attack < 85 ? m_attack + 15 : 100;
m_defense = m_defense < 90 ? m_defense + 10 : 100;
}
Memento* Save() // 游戏存档
{
return new Memento(m_vitality, m_attack, m_defense);
}
void Load(Memento* memento) // 加载状态
{
m_vitality = memento->GetVitality();
m_attack = memento->GetAttack();
m_defense = memento->GetDefense();
}
void ShowState()
{
std::cout<< "生命值:" << m_vitality <<std::endl
<< "攻击力:" << m_attack <<std::endl
<< "防御力:" << m_defense <<std::endl
<<std::endl;
}
private:
unsigned int m_vitality; // 生命值
unsigned int m_attack; // 攻击力
unsigned int m_defense; // 防御力
};
// 游戏状态保存类
class CareTake
{
public:
CareTake() {}
~CareTake()
{
for (auto iter = m_mementos.begin(); iter != m_mementos.end(); ++iter)
{
delete iter->second;
iter->second = nullptr;
}
m_mementos.clear();
}
Memento* GetState(std::string key)
{
std::map<std::string, Memento*>::iterator iter = m_mementos.find(key);
if (iter != m_mementos.cend())
return iter->second;
else
return nullptr;
}
// 已经存在key关键字,则插入失败
bool SetState(std::string key, Memento* memento)
{
auto ret = m_mementos.insert(std::make_pair(key, memento));
return ret.second;
}
private:
std::map<std::string, Memento*> m_mementos;
};
void MementoTest()
{
GameRole* pGameRole = new GameRole;
CareTake* pCareTake = new CareTake;
std::cout<< "----战斗前-----"<<std::endl;
pGameRole->ShowState();
pCareTake->SetState("战斗前", pGameRole->Save());
pGameRole->Attack();
std::cout<< "----战斗1后-----"<<std::endl;
pGameRole->ShowState();
pCareTake->SetState("战斗1后", pGameRole->Save());
pGameRole->Attack();
std::cout<< "----战斗2后-----"<<std::endl;
pGameRole->ShowState();
pCareTake->SetState("战斗2后", pGameRole->Save());
pGameRole->Resume();
std::cout<< "----恢复1后-----"<<std::endl;
pGameRole->ShowState();
pCareTake->SetState("恢复1后", pGameRole->Save());
pGameRole->Attack();
std::cout<< "----战斗3后-----"<<std::endl;
pGameRole->ShowState();
pCareTake->SetState("战斗3后", pGameRole->Save());
pGameRole->Load(pCareTake->GetState("战斗1后"));
std::cout<< "----恢复战斗1结果-----"<<std::endl;
pGameRole->ShowState();
pGameRole->Load(pCareTake->GetState("战斗前"));
std::cout<< "----恢复战斗前-----"<<std::endl;
pGameRole->ShowState();
delete pCareTake;
delete pGameRole;
pCareTake = nullptr;
pGameRole = nullptr;
}
#endif // MEMENTO_H