C++设计模式--备忘录模式

备忘录模式允许在不破坏封装性的情况下保存和恢复对象的状态。文章介绍了备忘录模式的定义、常用场景、优缺点,并通过C++代码展示了如何在游戏存档场景中应用该模式。
摘要由CSDN通过智能技术生成

备忘录模式(Memento Pattern)

定义

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

  • originator这个类是需要被保存状态的类;
  • Memento该类的对象由originator创建,主要用来保存originator的内部状态。
  • Careataker负责在需要的情况下去保存或者恢复originator的状态。

 

常用场景

  • 必须保存一个对象在某一时刻的状态,这样可以以后在需要的时候,恢复到当前状态;
  • 如果让其他对象直接保存当前对象的状态,将会暴露对象的实现细节,破坏对象的封装。

 

优缺点

优点:

  • 当发起人角色的状态有改变时,有可能是个错误的改变,我们使用备忘录模式就可以把这个错误改变还原。
  • 备份的状态是保存在发起人角色之外的,这样,发起人角色就不需要对各个备份的状态进行管理

缺点:

如果备份的对象存在大量的信息或者创建、恢复操作非常频繁,则可能造成很大的性能开销


C++实现

举例:游戏存档

大家都有过玩存档类(三国、世界足球等)的游戏,我们可以将某个游戏进度存档,然后在之后可以选择加载某个游戏状态,也可以恢复到最初始状态重新玩。

类图:
                 

代码:
 

/*!
*@file    Memento.h
*@brief   备忘录模式
*/

#ifndef MEMENTO_H
#define MEMENTO_H

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include <utility>

// 内部状态类
class Memento
{
public:
    Memento(unsigned int vitality, unsigned int attack, unsigned int defense)
        : m_vitality(vitality), m_attack(attack), m_defense(defense)
    {

    }

    ~Memento() {}

    void SetVitality(unsigned int vitality) {m_vitality = vitality;}
    void SetAttack(unsigned int attack) {m_attack = attack;}
    void SetDefense(unsigned int defense) {m_defense = defense;}

    unsigned int GetVitality() {return m_vitality;}
    unsigned int GetAttack() {return m_attack;}
    unsigned int GetDefense() {return m_defense;}

private:
    unsigned int m_vitality;   // 生命值
    unsigned int m_attack;     // 攻击力
    unsigned int m_defense;    // 防御力
};

// 游戏角色
class GameRole
{
public:
    GameRole() : m_vitality(100), m_attack(100), m_defense(100) {}
    ~GameRole() {}

    void Attack()
    {
        m_vitality = m_vitality > 8 ? m_vitality - 8 : 0;
        m_attack = m_attack > 10 ? m_attack - 10 : 0;
        m_defense = m_defense > 6 ? m_defense - 6 : 0;
    }

    void Resume()
    {
        m_vitality = m_vitality < 95 ? m_vitality + 5 : 100;
        m_attack = m_attack < 85 ? m_attack + 15 : 100;
        m_defense = m_defense < 90 ? m_defense + 10 : 100;
    }

    Memento* Save()  // 游戏存档
    {
        return new Memento(m_vitality, m_attack, m_defense);
    }

    void Load(Memento* memento)  // 加载状态
    {
        m_vitality = memento->GetVitality();
        m_attack = memento->GetAttack();
        m_defense = memento->GetDefense();
    }

    void ShowState()
    {
        std::cout<< "生命值:" << m_vitality <<std::endl
                 << "攻击力:" << m_attack <<std::endl
                 << "防御力:" << m_defense <<std::endl
                 <<std::endl;
    }

private:
    unsigned int m_vitality;   // 生命值
    unsigned int m_attack;     // 攻击力
    unsigned int m_defense;    // 防御力
};

// 游戏状态保存类
class CareTake
{
public:
    CareTake() {}
    ~CareTake()
    {
        for (auto iter = m_mementos.begin(); iter != m_mementos.end(); ++iter)
        {
            delete iter->second;
            iter->second = nullptr;
        }
        m_mementos.clear();
    }

    Memento* GetState(std::string key)
    {
        std::map<std::string, Memento*>::iterator iter = m_mementos.find(key);
        if (iter != m_mementos.cend())
            return iter->second;
        else
            return nullptr;
    }

    // 已经存在key关键字,则插入失败
    bool SetState(std::string key, Memento* memento)
    {
        auto ret = m_mementos.insert(std::make_pair(key, memento));
        return ret.second;
    }

private:
    std::map<std::string, Memento*> m_mementos;
};

void MementoTest()
{
    GameRole* pGameRole = new GameRole;
    CareTake* pCareTake = new CareTake;

    std::cout<< "----战斗前-----"<<std::endl;
    pGameRole->ShowState();
    pCareTake->SetState("战斗前", pGameRole->Save());

    pGameRole->Attack();

    std::cout<< "----战斗1后-----"<<std::endl;
    pGameRole->ShowState();
    pCareTake->SetState("战斗1后", pGameRole->Save());

    pGameRole->Attack();

    std::cout<< "----战斗2后-----"<<std::endl;
    pGameRole->ShowState();
    pCareTake->SetState("战斗2后", pGameRole->Save());

    pGameRole->Resume();

    std::cout<< "----恢复1后-----"<<std::endl;
    pGameRole->ShowState();
    pCareTake->SetState("恢复1后", pGameRole->Save());

    pGameRole->Attack();

    std::cout<< "----战斗3后-----"<<std::endl;
    pGameRole->ShowState();
    pCareTake->SetState("战斗3后", pGameRole->Save());

    pGameRole->Load(pCareTake->GetState("战斗1后"));

    std::cout<< "----恢复战斗1结果-----"<<std::endl;
    pGameRole->ShowState();

    pGameRole->Load(pCareTake->GetState("战斗前"));

    std::cout<< "----恢复战斗前-----"<<std::endl;
    pGameRole->ShowState();

    delete pCareTake;
    delete pGameRole;

    pCareTake = nullptr;
    pGameRole = nullptr;

}

#endif // MEMENTO_H

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值