C++设计模式——备忘录模式(Memento Pattern)

C++设计模式——备忘录模式(Memento Pattern)

微信公众号:幼儿园的学霸

目录

定义

Without violating encapsulation, capture and externalize an object’s internal state so that the object can be restored to this state later
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态

备忘录模式:保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。

备忘录模式主要应用于备份或者回退操作,为了使软件使用更友好,通常都有回退功能,软件一般也要提供回退机制,而要实现回退,就必须事先备份好状态信息,所以有了备忘录模式就有实现系统回退到某一个特定的历史状态。

备忘录对象用于存储另外一个对象内部状态的快照对象,所以备忘录模式又可以称之为快照模式(Snapshot Pattern)或Token模式

其UML类图如下所示:
备忘录模式UML类图
主要角色如下:

  • 备忘录角色(Memento): 负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人;
  • 发起人角色(Originator): 记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,可以根据需要决定备忘录角色中保存自身的哪些内部状态,能够访问备忘录里的所有信息;
  • 管理者角色(Caretaker): 对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改,只能够将备忘录传递给其他对象。

代码示例

游戏存档为例,看一下如何用备忘录模式实现

#include <bits/stdc++.h>

//
//备忘录模式
//关键代码:Memento类、Originator类、Caretaker类;
// Originator类不与Memento类耦合,而是与Caretaker类耦合
//


//需要保存的信息
//此处将需要保存的信息提取出来放在一个结构体中
//也可以不用放在结构体中,直接作为类的成员变量
typedef struct {
    int nHp;//血量
    int nMp;//蓝量
    int nAttack;//攻击
}GameValue;


//备忘录类
class Memento{
public:
    Memento(const GameValue& gameValue):m_gameValue(gameValue){}

    //函数前后均加const
    //前const:返回的变量不可修改
    //后const:该函数readonly,表示该类的this指针为const类型,
    // 不能改变类的成员变量的值
    const GameValue& getValue() const{
        return m_gameValue;
    }


    //Memento() = delete;
    //Memento(const Memento &) = delete;
    //Memento &operator=(const Memento &) = delete;

private:
    GameValue m_gameValue;
};

//管理者角色
class Caretaker
{
public:
    const std::shared_ptr<Memento> GetState(const std::string& key) {
        return mData[key];
    }
    void SetState(const std::string& key,
            std::shared_ptr<Memento> pMemento) {
        mData[key] = pMemento;
    }

private:
    //此处考虑在map中存储指针,而非直接存储对象
    std::map<std::string,std::shared_ptr<Memento>> mData;
};

//发起人角色
class Hero{
public:
    Hero()
    :m_gameValue{100,100,100}{
    }

    Hero(const GameValue& gameValue)
    :m_gameValue(gameValue){
    }

    //保存当前信息
    void saveState(const std::string& key) {
        m_Caretaker.SetState(key, std::make_shared<Memento>(m_gameValue));
    }

    //恢复信息
    const void resumeState(const std::string& key) {
        m_gameValue = m_Caretaker.GetState(key)->getValue();
    }

    void battle()
    {
        m_gameValue.nHp = rand()%100;
        m_gameValue.nMp = rand()%100;
        m_gameValue.nAttack = rand()%100;
    }

    void showState() {
        std::cout<<"血量:"<<m_gameValue.nHp<<std::endl
                <<"蓝量:"<<m_gameValue.nMp<<std::endl
                <<"攻击:"<<m_gameValue.nAttack<<std::endl;
    }

private:
    GameValue m_gameValue;
    Caretaker m_Caretaker;//常规对象,没有必要用指针
};

int main()
{
    Hero hero;

    std::cout<<"----战斗前-----"<<std::endl;
    hero.showState();
    std::cout<<std::endl;
    hero.saveState("战斗前");

    hero.battle();
    std::cout<<"-----战斗1后-----"<<std::endl;
    hero.showState();
    std::cout<<std::endl;
    hero.saveState("战斗1后");

    hero.battle();
    std::cout<<"-----战斗2后-----"<<std::endl;
    hero.showState();
    hero.saveState("战斗2后");
    std::cout<<std::endl;

    hero.battle();
    std::cout<<"-----战斗3后-----"<<std::endl;
    hero.showState();
    hero.saveState("战斗3后");
    std::cout<<std::endl;

    hero.resumeState("战斗1后");
    std::cout<<"-----恢复战斗1结果-----"<<std::endl;
    hero.showState();
    std::cout<<std::endl;

    hero.resumeState("战斗前");
    std::cout<<"-----恢复战斗前-----"<<std::endl;
    hero.showState();
    std::cout<<std::endl;

    return 0;
    //运行结果如下:
    //----战斗前-----
    //血量:100
    //蓝量:100
    //攻击:100
    //
    //-----战斗1后-----
    //血量:83
    //蓝量:86
    //攻击:77
    //
    //-----战斗2后-----
    //血量:15
    //蓝量:93
    //攻击:35
    //
    //-----战斗3后-----
    //血量:86
    //蓝量:92
    //攻击:49
    //
    //-----恢复战斗1结果-----
    //血量:83
    //蓝量:86
    //攻击:77
    //
    //-----恢复战斗前-----
    //血量:100
    //蓝量:100
    //攻击:100
}

总结

  • 备忘录模式与原型模式:
    原型模式也能保存一个对象在某一个时刻的状态,那么两者有何不同的呢?原型模式保存的是当前对象的所有状态信息,恢复的时候会生成与保存的对象完全相同的另外一个实例;而备忘录模式保存的是我们关心的在恢复时需要的对象的部分状态信息,相当于快照。

  • 优点: 1.给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态; 2.实现了信息的封装,使得用户不需要关心状态的保存细节。

  • 缺点:消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。

  • 使用场景: 1、需要保存/恢复数据的相关状态场景;2、提供一个可回滚的操作。

  • 应用实例: 1.Windows 里的 ctri + z;2.浏览器的后退;3.虚拟机的快照与恢复;4.git版本管理;5.棋牌游戏的悔牌操作。

参考资料

1.备忘录模式(详解版)
2.备忘录模式(Memento)C++实现



下面的是我的公众号二维码图片,按需关注
图注:幼儿园的学霸

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
备忘录模式是一种行为型设计模式,它允许在不破坏封装性的前提下捕获并保存一个对象的内部状态,并在需要时恢复该状态。在软件开发中,备忘录模式通常用于实现撤销操作或者历史记录功能。 下面是一个使用备忘录模式的简单示例,假设我们有一个文本编辑器,用户可以在其中输入文本并进行编辑操作。我们希望实现一个撤销功能,使得用户可以撤销之前的编辑操作。 首先,我们需要定义一个备忘录类,用于保存编辑器的状态: ```python class EditorMemento: def __init__(self, content): self.content = content def get_content(self): return self.content ``` 然后,我们需要定义一个编辑器类,其中包含了一些编辑操作,以及用于保存和恢复状态的方法: ```python class Editor: def __init__(self): self.content = "" def type(self, words): self.content = self.content + " " + words def delete(self, words): if words in self.content: self.content = self.content.replace(words, "") def save(self): return EditorMemento(self.content) def restore(self, memento): self.content = memento.get_content() ``` 最后,我们可以使用这个编辑器类来实现撤销功能: ```python editor = Editor() editor.type("This is the first sentence.") editor.type("This is the second sentence.") saved = editor.save() editor.delete("second") print(editor.content) # 输出:This is the first sentence. editor.restore(saved) print(editor.content) # 输出:This is the first sentence. This is the second sentence. ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值