《C++新经典设计模式》之第18章 备忘录模式

《C++新经典设计模式》之第18章 备忘录模式

备忘录模式.cpp
cpp 复制代码
#include <iostream>
#include <vector>
#include <memory>
using namespace std;

// 保存对象内部状态,必要时恢复
// 在不破坏封装性的前提下,捕获对象的内部状态并保存,之后可将对象恢复到原先保存的状态
// 3种角色
// Originator(原发器),普通业务类,可以创建备忘录用于保存其当前的内部状态,之后用备忘录恢复内部状态
// Memento(备忘录),存储原发器对象某个瞬间的内部状态
// CareTaker(负责人/管理者),保存和传递备忘录,不知道备忘录细节,不能检查或操作备忘录

namespace ns1
{
    class FighterMemento // 玩家主角相关的备忘录类
    {
        friend class Fighter; // 友元类Fighter可以访问本类的私有成员函数

        // 玩家主角类中要保存起来的数据,就放到这里来
        int m_life;   // 生命值
        int m_magic;  // 魔法值
        int m_attack; // 攻击力

    private: // 构造函数,用private修饰以防止在外部被随意创建
        FighterMemento(int life, int magic, int attack) : m_life(life), m_magic(magic), m_attack(attack) {}

    private: // 提供一些供Fighter类来访问的接口,用private修饰防止被任意类访问
        int getLife() const { return m_life; }
        void setLife(int life) { m_life = life; }
        int getMagic() const { return m_magic; }
        void setMagic(int magic) { m_magic = magic; }
        int getAttack() const { return m_attack; }
        void setAttack(int attack) { m_attack = attack; }
    };

    class Fighter     // 玩家主角类
    {                 // 角色属性
        int m_life;   // 生命值
        int m_magic;  // 魔法值
        int m_attack; // 攻击力
    public:
        Fighter(int life, int magic, int attack) : m_life(life), m_magic(magic), m_attack(attack) {}

    public: // 将玩家数据写入备忘录(创建备忘录,并在其中存储了当前状态)
        shared_ptr<FighterMemento> createMomento() const
        {
            shared_ptr<FighterMemento> back(new FighterMemento(m_life, m_magic, m_attack));
            return back;
            // return make_shared<FighterMemento>(m_life, m_magic, m_attack);
        }
        void restoreMomento(const shared_ptr<FighterMemento> &pfm) // 从备忘录中恢复玩家数据
        {
            m_life = pfm->m_life; // 友元类
            m_magic = pfm->getMagic();
            m_attack = pfm->getAttack();
        }
        void setToDead() { m_life = 0; } // 为测试目的引入的接口,设置玩家的生命值为0(玩家死亡)
        void displayInfo() const         // 用于输出一些信息
        {
            cout << "The player's current HP, magic and attack power are respectively " << m_life << ", " << m_magic << ", " << m_attack << endl;
        }
    };

    class FCareTaker // 管理者(负责人)类
    {
        shared_ptr<FighterMemento> m_pfm; // 指向备忘录对象的指针
    public:
        FCareTaker(const shared_ptr<FighterMemento> &ptmpfm = nullptr) : m_pfm(ptmpfm) {} // 形参是指向备忘录对象的指针
        shared_ptr<FighterMemento> getMemento() const { return m_pfm; }                   // 获取指向备忘录对象的指针
        void setMemento(const shared_ptr<FighterMemento> &ptmpfm) { m_pfm = ptmpfm; }     // 保存指向备忘录对象的指针
    };

    class FCareTaker2 // 支持多个快照的负责人(管理者)类
    {
        vector<shared_ptr<FighterMemento>> m_pfmContainer; // 存储备忘录对象指针的容器

    public:
        void push(const shared_ptr<FighterMemento> &ptmpfm) { m_pfmContainer.emplace_back(ptmpfm); } // 保存指向备忘录对象的指针
        shared_ptr<FighterMemento> pop()
        {
            if (m_pfmContainer.empty())
                return nullptr;
            return m_pfmContainer.back();
        }
        shared_ptr<FighterMemento> getMemento(int index) const // 获取指向备忘录对象的指针
        {
            if (index >= 0 && index < m_pfmContainer.size())
                return m_pfmContainer[index];
            return nullptr;
        }
    };
}

int main()
{
#if 0
    using namespace ns1;
    shared_ptr<Fighter> p_fighter(new Fighter(800, 200, 300));
    
    // (1)显示玩家主角在与BOSS战斗之前的信息
    p_fighter->displayInfo();

    // (2)为玩家主角类对象创建一个备忘录对象(其中保存了当前主角类对象中的必要信息)
    shared_ptr<FighterMemento> p_fighterMemo = p_fighter->createMomento();

    // (3)玩家与BOSS开始战斗
    cout << "The protagonist of the player and BOSS began to fight fiercely------" << endl;
    p_fighter->setToDead();   // 玩家主角在与BOSS战斗中,生命值最终变成0而死亡(被BOSS击败)
    p_fighter->displayInfo(); // 显示玩家主角在与BOSS战斗之后的信息

    // (4)因为在与BOSS战斗之前已经通过NPC保存了游戏进度,这里模拟载入游戏进度,恢复玩家主角类对象的数据,让其可以与BOSS再次战斗
    cout << "Players recover their information through memos------" << endl;
    p_fighter->restoreMomento(p_fighterMemo);
    p_fighter->displayInfo(); // 显示玩家主角通过备忘录恢复到战斗之前的信息
#endif

#if 0
    using namespace ns1;
    shared_ptr<Fighter> p_fighter(new Fighter(800, 200, 300));

    // (1)显示玩家主角在与BOSS战斗之前的信息
    p_fighter->displayInfo();

    // (2)为玩家主角类对象创建一个备忘录对象(其中保存了当前主角类对象中的必要信息)
    shared_ptr<FCareTaker> pfcaretaker(new FCareTaker(p_fighter->createMomento()));

    // (3)玩家与BOSS开始战斗
    cout << "The protagonist of the player and BOSS began to fight fiercely------" << endl;
    p_fighter->setToDead();   // 玩家主角在与BOSS战斗中,生命值最终变成0而死亡(被BOSS击败)
    p_fighter->displayInfo(); // 显示玩家主角在与BOSS战斗之后的信息

    // (4)因为在与BOSS战斗之前已经通过NPC保存了游戏进度,这里模拟载入游戏进度,恢复玩家主角类对象的数据,让其可以与BOSS再次战斗
    cout << "Players recover their information through memos------" << endl;
    p_fighter->restoreMomento(pfcaretaker->getMemento());
    p_fighter->displayInfo(); // 显示玩家主角通过备忘录恢复到战斗之前的信息
#endif

#if 1
    using namespace ns1;
    shared_ptr<Fighter> p_fighter2(new Fighter(800, 200, 300));
    shared_ptr<FCareTaker2> pfcaretaker2(new FCareTaker2());
    pfcaretaker2->push(p_fighter2->createMomento()); // 做第一次快照吗,此快照玩家生命值为800
    p_fighter2->setToDead();                         // 改变玩家主角的生命值
    pfcaretaker2->push(p_fighter2->createMomento()); // 做第二次快照,此快照玩家生命值为0
    p_fighter2->displayInfo();                       // 玩家主角生命值应该为0
    cout << "------------------" << endl;
    // 当前玩家生命值为0,恢复第一次快照,也就是恢复玩家生命值为800
    p_fighter2->restoreMomento(pfcaretaker2->getMemento(0));
    p_fighter2->displayInfo(); // 玩家主角生命值应该恢复为800
#endif

    cout << "Over!\n";
    return 0;
}
相关推荐
李元豪3 小时前
【智鹿空间】c++实现了一个简单的链表数据结构 MyList,其中包含基本的 Get 和 Modify 操作,
数据结构·c++·链表
UestcXiye3 小时前
《TCP/IP网络编程》学习笔记 | Chapter 9:套接字的多种可选项
c++·计算机网络·ip·tcp
一丝晨光4 小时前
编译器、IDE对C/C++新标准的支持
c语言·开发语言·c++·ide·msvc·visual studio·gcc
丶Darling.4 小时前
Day40 | 动态规划 :完全背包应用 组合总和IV(类比爬楼梯)
c++·算法·动态规划·记忆化搜索·回溯
奶味少女酱~5 小时前
常用的c++特性-->day02
开发语言·c++·算法
我是哈哈hh5 小时前
专题十八_动态规划_斐波那契数列模型_路径问题_算法专题详细总结
c++·算法·动态规划
_小柏_6 小时前
C/C++基础知识复习(15)
c语言·c++
_oP_i7 小时前
cmake could not find a package configuration file provided by “Microsoft.GSL“
c++
mingshili7 小时前
[python] 如何debug python脚本中C++后端的core dump
c++·python·debug
PaLu-LI7 小时前
ORB-SLAM2源码学习:Frame.cc: Frame::isInFrustum 判断地图点是否在当前帧的视野范围内
c++·人工智能·opencv·学习·算法·ubuntu·计算机视觉