1. 备忘录模式
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。比如存储游戏进度,撤销操作。
2. 结构图
3. 适用
Memento 模式比较适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存的属性只是众多属性中的一小部分时,Originator 可以根据保存的Memento 信息还原到前一状态。
4. example
游戏角色状态保存备忘录:
角色有生命值 攻击力 防御力这几个属性,战斗后会消耗这些属性。
如果需要保存角色的状态,可以先创建一个备忘录类封装在游戏管理者类中,通过游戏管理者实例和角色的交互实现对角色的状态的恢复。
// 备忘录 保存角色的属性值
class Memento
{
int vitality; // 生命力
int attack; // 攻击力
int defense; // 防御力
public:
Memento(){};
Memento(int v, int a, int d)
{
vitality = v;
attack = a;
defense = d;
}
int getV() { return vitality; }
int getA() { return attack; }
int getD() { return defense; }
};
// 游戏角色 有状态保存 状态恢复 战斗等成员方法
class Role
{
int vitality; // 生命力
int attack; // 攻击力
int defense; // 防御力
public:
// 保存角色状态
Memento saveMemento()
{
return Memento(vitality, attack, defense);
}
// 恢复角色状态
void backMemento(Memento m)
{
vitality = m.getV();
attack = m.getA();
defense = m.getD();
}
// 设置角色状态
void setV(int v) { vitality = v; }
void setD(int d) { defense = d; }
void setA(int a) { attack = a; }
void setAll(int v, int a, int d)
{
vitality = v;
attack = a;
defense = d;
}
// 战斗
void fight(){
vitality -= 10;
attack -= 5;
defense -= 5;
}
// 角色状态查看
void show()
{
printf("vitality: %d; attack: %d; defense: %d.\n", vitality, attack, defense);
}
};
// 备忘录的管理者
class Caretaker
{
Memento m;// 没有默认构造函数的成员变量必须初始化
public:
void setMem(Memento mem){
m = mem;
}
Memento getMem(){
return m;
}
};
int main()
{
Role r;
r.setAll(20, 20, 20);
r.show();
// Memento m = r.saveMemento(); 如果直接这样操作 外界能直接访问游戏角色保存的状态
Caretaker c;
c.setMem(r.saveMemento());
r.fight();// 打架过后 元气大伤
r.show();
r.backMemento(c.getMem()); // 通过管理者做一层封装 外界不能更改备忘录状态
r.show();
return 0;
}
注意
- 另外用一个管理者封装备忘录,可防止备忘录直接被外部修改。
- 没有默认构造函数的成员变量必须初始化。
- 备忘录模式也有缺点,角色状态需要完整存储到备忘录对象中,如果状态数据很大很多,那么在资源消耗上,备忘录对象会非常耗内存。