备忘录模式(Memento)


前言

        本周五参加了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());

总结

         备忘录模式通常跟命令模式配合使用,在命令执行前保存状态,在撤销命令时恢复执行器的状态,这也是备忘录模式的另一个经典使用场景。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值