设计模式之备忘录模式

Posted tobeexpert

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之备忘录模式相关的知识,希望对你有一定的参考价值。

2018-09-22 22:35:23

备忘录模式

  备忘录(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原来保存的状态。

备忘录模式UML类图

技术分享图片

Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可以使用备忘录恢复内部状态。Originator可根据需要决定Memento存储Originator的哪些内部状态。

Memento(备忘录):负责存储Originator对象的内部状态,并可防止Originator以外的其它对象访问备忘录Memento。备忘录有两个接口,Cartaker只能看到备忘录的窄接口,它只能将备忘录传递给其它对象。Originator能看到一个宽接口,允许它访问返回到先前状态所需的所有数据。

Caretaker(管理者):负责保存好备忘录Memento,不能对备忘录的内容进行操作或者检查。

优缺点

优点:

  1.提供了一种状态恢复机制,把要保存的细节封装在了Memento中,使用户能够方便的回到某个历史状态,如果需要更改保存的细节,也不会对客户端产生影响。

  2.实现了信息的封装,使用户不需要关心保存信息的细节。

缺点:

  1.角色状态需要完整存储到备忘录对象中,如果状态数据很多很大,那么在资源消耗上,备忘录对象会非常消耗内存。

适用场景:

  Memento模式比较适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存的属性只是众多属性中的一小部分时,Originator可以根据保存的Memento信息还原到前一状态,有时一些对象的内部信息必须保存在对象以外的地方,但是必须由对象自己读取,这是使用备忘录可以把复杂的对象内部信息对其它的对象屏蔽起来。作用是,当角色的状态改变的时候,有可能这个状态无效,这时候就可以使用暂时存储起来的备忘录将状态复原。

代码示例

  (都是《大话设计模式》这本书的内容呀)背景:游戏进度备忘。假设我们需要保存的游戏角色的属性有:蓝量、血量、以及攻击力、防御力四个。

1.Originator类。打游戏的时候只有角色自己拥有恢复存档和保存进度的能力

技术分享图片
#ifndef ORIGINATOR_H_
#define ORIGINATOR_H_
//这个类在本例中是游戏角色类
//假设你正在玩某个游戏,回忆一下,具有存档和读取存档数据的是不是只有你的游戏角色呢?
#include "Memento.h"
#include <string>
#include <iostream>

class Originator
{
public:
    Memento createMemento()
    {
    return Memento(m_iLifeValues,m_iMP,m_iATK,m_iDef);    //创建一个备忘录,将当前需要保存的信息导入,并实例化出一个Memento对象
    }
    //从备忘录中恢复存档(为什么需要这个函数呢,你想一下,你在存档之后,下机了,下次再登录进入游戏,要恢复存档,数据必然要从某个地方读入,所以这个函数是必须的
    void restoreMemento(Memento objMemento)
    {
    m_iLifeValues = objMemento.getLifeValues();
        m_iMP = objMemento.getMP();
        m_iATK = objMemento.getATK();
        m_iDef = objMemento.getDef();
    }
    
    //显示属性值
    void show() const
    {
    std::cout << "Name: " << m_strRoleName << " LifeValues:" << m_iLifeValues << " MP:" << m_iMP << " ATK:" << m_iATK << " Def:" << m_iDef <<std::endl;
    }
    //设置属性的初始值
    void setInit(const int iLifeValues,const int iMP,const int iATK, const int iDef)  
    {
    m_iLifeValues = iLifeValues;
        m_iMP = iMP;
    m_iATK = iATK;
    m_iDef = iDef;
    }
    
    //和Boss玩玩,给你一下各项属性减去100(随便写的,所以结果可能出现负值)
    //返回值为false,则表示Game over
    bool beatAMonster()
    {
    m_iLifeValues -=100;
        m_iMP -= 100;
    m_iATK -=100;
    m_iDef -=100;
    if(0>= m_iLifeValues)
    {
        return false;
        }
    return true;
    }
    
    Originator(const std::string strRoleName) : m_strRoleName(strRoleName){};
    ~Originator() = default;
private:
    //游戏角色的属性:生命值、魔法值、攻击力、防御力
    int m_iLifeValues{0};    //生命值
    int m_iMP{0};    //魔法值
    int m_iATK{0};    //攻击力
    int m_iDef{0};    //防御值
    std::string m_strRoleName;
};
#endif
Originator

2.Mementor类。备忘录,用于保存Originator类内部状态的外部类

技术分享图片
#ifndef MEMENTO_H_
#define MEMENTO_H_
//备忘录类,负责保存属性
class Memento
{
public:
    //读取存档生命值
    int getLifeValues() const
    {
    return m_iLifeValues;
    }
    //读取魔法存档值
    int getMP() const
    {
    return m_iMP;
    }
    //读取攻击力存档
    int getATK() const
    {
    return m_iATK;
    }
    //读取防御力存档
    int getDef() const
    {
    return m_iDef;
    }
    Memento(const int iLifeValues,const int iMP,const int iATK,const int iDef):m_iLifeValues(iLifeValues),m_iMP(iMP),m_iATK(iATK),m_iDef(iDef){};
    Memento(const Memento& objMemento)
    {
    m_iLifeValues = objMemento.getLifeValues();
    m_iMP = objMemento.getMP();
    m_iATK = objMemento.getATK();
        m_iDef = objMemento.getDef();
    }
    Memento() = default;
    ~Memento() = default;
private:
    int m_iLifeValues{0};    //生命值
    int m_iMP{0};    //魔法值
    int m_iATK{0};    //攻击力
    int m_iDef{0};    //防御力
};
#endif
Memento

3.Caretaker类。备忘录的管理类。

技术分享图片
#ifndef CARETAKER_H_
#define CARETAKER_H_
//管理者,这个类用来管理备忘录,它的作用,就是从加载备忘录的内容,将其恢复到某个对象

#include "Memento.h"

class Caretaker
{
public:
    //设置备忘录
    void setMemento(Memento objMemento)
    {
    m_Memento = objMemento;
    }
    Memento getMemento()
    {
    return m_Memento;
    }
private:
    Memento m_Memento;        //持有一个备忘录对象,它是Caretaker进行备忘录管理的关键
};
#endif
Caretaker

4.client

技术分享图片
#include "Caretaker.h"
#include "Originator.h"

using namespace std;

int main(int argc,char *argv[])
{
    //创建一个游戏角色
    Originator objOriginator("ChongLou");
    //设置初始属性
    objOriginator.setInit(100,100,100,100);
    //保存初始状态
    Caretaker objCaretaker;
    objCaretaker.setMemento(objOriginator.createMemento());
    //显示初始状态
    objOriginator.show();
    //开始打怪
    objOriginator.beatAMonster();
    //显示打怪后的属性
    objOriginator.show();
    //加载存档
    objOriginator.restoreMemento(objCaretaker.getMemento());
    //显示加载存档后的属性
    objOriginator.show();
    return(1);
}
Client

 

以上是关于设计模式之备忘录模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之- 备忘录模式(Memento Pattern)

设计模式之备忘录模式

JAVA SCRIPT设计模式--行为型--设计模式之Memnto备忘录模式(18)

JAVA SCRIPT设计模式--行为型--设计模式之Memnto备忘录模式(18)

行为型设计模式之备忘录模式

行为型设计模式之备忘录模式