前言
本周五参加了Memento(备忘录 )模式研讨会,本文的目的是对这个模式的总结和分享,希望对需要学习这个设计模式的同学有所帮助。本文一共分为两个部分,第一个部分是备忘录模式的基础知识总结;第二个部分是分享备忘录模式简单示例。一、备忘录模式总结
1、模式意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。2、参与者
Memento 备忘录
– 备忘录存储原发器对象的内部状态;防止原发器以外的其他对象访问备忘录;
– 备忘录实际上有两个接口,管理者只能看到备忘录的窄接口,它只能将备忘录传递给其他对象;原发器能看到备忘录的宽接口,允许它访问返回到原先状态所需要的所有数据;
Originator 原发器
– 原发器创建一个备忘录,用来记录当前时刻它的内部状态;
– 使用备忘录恢复内部状态;
Caretaker 管理者
– 保存备忘录;
– 不能对备忘录的内容进行操作或检查;
3、结构、协作、适用性及效果
结构图:1、管理者在需要备份状态的时候,请求原发器创建一个备忘录,然后保存;
2、管理者在恢复状态的时候,给原发器设置状态,原发器从备忘录取出装备,并恢复到备忘录保存的状态。
1、必须保存一个对象在某个时刻的(部分)状态,以便需要的时候恢复到先前状态。
2、如果一个接口让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
效果:
1、保持封装边界。
2、简化了原发器。使用备忘录可以避免暴露一些只应由原发器管理,却又必须存储在原发器之外的信息。该模式把可能很复杂的原发器内部信息对其他对象屏蔽起来,从而保持了封装边界.
备忘录对象交由管理者管理,避免原发器包含备忘录的管理源码,简化了原发器的设计。
3、使用备忘录可能代价很高。
4、定义窄接口和宽接口。如果原发器在生成备忘录时,必须拷贝并存储大量的信息,或者客户非常频繁的创建备忘录和恢复原发器状态,可能导致非常大的开销。
5、维护备忘录的潜在代价。对于一些语言,很难保证只有原发器能访问备忘录的状态。
管理者负责删除它所维护的备忘录,然而,管理者不知道备忘录有多少个状态。因此,当存储备忘录时,一个本来很小的管理者可能会产生大量的存储开销。
二、备忘录模式简单示例
1、用例描述
一般游戏都会提供游戏进度保存功能,保存当前的游戏角色状态,当需要回滚重玩时,只需要读取保存的档案即可恢复到保存时的状态,这就是备忘录模式一个典型的用例场景。以下使用简单的代码来演示备份和恢复(存档/读档),了解备忘录模式的使用方式。2、示例代码
class Role;
//角色属性备忘录
class RoleMemento {
public:
~RoleMemento();
private:
int get_level() {return m_level;}
void set_level(int l) {m_level = l;}
int get_attack() {return m_attack;}
void set_attack(int a) {m_attack = a;}
int get_defense() { return m_defense;}
void set_defense(int d) {m_defense = d;}
int get_vitality() {return m_vitality;}
void set_vitality(int v) {m_vitality = v;}
friend class Role;
int m_level; // 等级
int m_attack; // 攻击力
int m_defense; // 防御力
int m_vitality;// 生命值
};
//游戏角色
class Role {
public:
Role();
RoleMemento* save_role_state();
void recover_role_state(RoleMemento* role_memento);
void init();
void fight(int n);
private:
int m_level; // 等级
int m_attack; // 攻击力
int m_defense; // 防御力
int m_vitality;// 生命值
};
RoleMemento* Role::save_role_state() {
RoleMemento* new_role = new RoleMemento();
new_role->set_level(m_level);
new_role->set_attack(m_attack);
new_role->set_defense(m_defense);
new_role->set_vitality(m_vitality);
return new_role;
}
void Role::recover_role_state(RoleMemento* role_memento) {
m_level = role_memento->get_level();
m_attack = role_memento->get_attack();
m_defense = role_memento->get_defense();
m_vitality = role_memento->get_vitality();
}
//游戏存档管理器
class MementoManager {
public:
void set_memento(RoleMemento* memento) {m_role_memento = memento;}
RoleMemento* get_memento() {return m_role_memento;}
private:
RoleMemento* m_role_memento;
};
//使用
MementoManager *memento_manager = new MementoManager;
Role* role_1 = new Role;
role_1->init();
//存档
memento_manager->set_memento(role_1 ->save_role_state());
...
//玩游戏
role_1->fight(1);
....
//读档
role_1->recover_role_state(memento_manager->get_memento());