C++设计模式——Memento备忘录模式

一,备忘录模式的定义

备忘录模式是一种行为型设计模式,它允许将对象的状态保存在外部,并在需要时恢复。

备忘录模式允许在不破坏封装性的前提下,捕获并存储一个对象的内部状态,并在需要时将其恢复到之前的状态。

在某些开发场景,备忘录模式可以用于缓存函数的结果,避免重复计算,以提高性能。

在软件开发中,备忘录模式常应用于某些计算密集型、IO密集型的操作场景,例如数据分析、图形处理等。

备忘录模式在现实生活中的抽象实例:

文本编辑器:当我们在文本编辑器中进行编辑操作时,可以使用撤销功能恢复到之前的状态。

游戏存档:我们可以在游戏中存档,以便下次打开时恢复到之前的游戏进度。

浏览器的缓存:浏览器中的历史记录可以帮助我们返回到之前访问的页面。

操作系统:在操作系统中,我们可以使用撤销功能来避免误操作。

二,备忘录模式的结构

备忘录模式主要包含以下组件:

1.发起人(Originator):

它会在需要保存自身状态时创建一个备忘录对象,并在后续场景使用备忘录对象来恢复自身状态。

2.备忘录(Memento):

用来获取和设置对象的内部状态。

3.管理者(Caretaker):

用来管理多个备忘录对象。

组件之间的工作步骤如下:

1.客户端创建和使用发起人对象。发起人对象可以有一个内部状态,客户端可以改变该状态。

2.客户端通过调用发起人对象的方法来创建备忘录对象,并将发起人对象的当前状态保存到备忘录中。

3.客户端将备忘录对象交给管理者对象进行保存。

4.在需要时,客户端可以从管理者对象获取备忘录对象,并将发起人对象的状态恢复到备忘录对象所保存的状态。

备忘录模式的核心在于,发起人对象和管理者对象之间是分离的,保证了发起人对象的状态可以在不影响封装性和隐藏性的情况下被保存和恢复。

对应UML类图:

三,备忘录模式代码样例

Demo1:

cpp 复制代码
#include <iostream>
#include <string>
#include <vector>

class Originator {
private:
       std::string state;
public:
       void SetState(const std::string& newState) {
              state = newState;
       }
       std::string GetState() const {
              return state;
       }
       class Memento {
       private:
              std::string state;
       public:
              Memento(const std::string& originatorState){
                      state = originatorState;
              }
              std::string GetSavedState() const {
                      return state;
              }
       };
       Memento CreateMemento() const {
              return Memento(state);
       }
       void RestoreState(const Memento& memento) {
              state = memento.GetSavedState();
       }
};

class Caretaker {
private:
       std::vector<Originator::Memento> mementos;
public:
       void AddMemento(const Originator::Memento& memento) {
              mementos.push_back(memento);
       }
       Originator::Memento GetMemento(int index) const {
              if (index >= 0 && index < mementos.size()) {
                      return mementos[index];
              }
              throw std::out_of_range("Invalid Memento index");
       }
};

int main() {
       Originator originator;
       Caretaker caretaker;

       originator.SetState("State 1");
       caretaker.AddMemento(originator.CreateMemento());
       originator.SetState("State 2");
       caretaker.AddMemento(originator.CreateMemento());
       originator.SetState("State 3");
       caretaker.AddMemento(originator.CreateMemento());

       std::cout << "Current state: "
              << originator.GetState() << std::endl;
       originator.RestoreState(caretaker.GetMemento(2));
       std::cout << "Current state: "
              << originator.GetState() << std::endl;

       return 0;
}

运行结果:

bash 复制代码
Current state: State 3
Current state: State 3

Demo2:

cpp 复制代码
#include <iostream>
#include <string>
#include <vector>

class Memento {
private:
    int state;
public:
    Memento(int s) : state(s) {}
    int getState() const { return state; }
};

class Originator {
private:
    int currentState;
public:
    void setState(int newState) {
        currentState = newState;
    }
    Memento createMemento() {
        return Memento(currentState);
    }
    void restoreFromMemento(Memento& memento) {
        currentState = memento.getState();
    }
    void getState() {
        std::cout << "Current state: " << currentState << std::endl;
    }
};

class CareTaker {
private:
    std::vector<Memento> memoranda;
public:
    void saveMemento(Originator& originator) {
        memoranda.push_back(originator.createMemento());
    }
    void restoreOriginatorToState(Originator& originator, size_t index) {
        originator.restoreFromMemento(memoranda[index]);
    }
    Memento getMemento(int index) const {
        if (index >= 0 && index < memoranda.size()) {
            return memoranda[index];
        }
        throw std::out_of_range("Invalid Memento index");
    }
};

int main() {
    Originator originator;
    CareTaker caretaker;

    originator.setState(5);
    caretaker.saveMemento(originator);
    originator.getState();

    originator.setState(10);
    caretaker.saveMemento(originator);
    originator.getState();

    originator.setState(15);
    caretaker.saveMemento(originator);
    originator.getState();

    originator.setState(20);
    originator.getState();

    caretaker.restoreOriginatorToState(originator, 1);
    originator.getState();
    return 0;
}

运行结果:

bash 复制代码
Current state: 5
Current state: 10
Current state: 15
Current state: 20
Current state: 10

四,备忘录模式的应用场景

网络请求:当网络服务频繁收到请求时,备忘录模式可以缓存响应结果,降低网络延迟。

算法优化:搜索或排序算法可能存在递归操作,备忘录模式可以帮助记录中间结果,避免重复搜索。

图形渲染:在游戏或图形等开发场景,备忘录模式可以避免复杂的图形结构被反复渲染。

五,备忘录模式的优缺点

备忘录模式的优点:

提供了对象状态的保存和恢复功能,使得系统更加灵活。

提供了一种简单的撤销/重做机制。

通过将结果进行缓存,避免了重复处理,提升了系统性能。

备忘录模式的缺点:

如果需要保存的状态数量很多,可能会占用较多的内存。

如果没有对外部访问备忘录对象的权限进行限制,可能会破坏封装性。

如果应用不当会使得代码结构更加复杂。

六,代码实战

Demo:模拟文本编辑器的撤销功能

cpp 复制代码
#include <iostream>
#include <string>
#include <vector>

class TextMemento {
public:
    TextMemento(const std::string& text){
        text_ = text;
    }
    const std::string& getText() const {
        return text_;
    }
private:
    std::string text_;
};

class TextEditor {
public:
    void setText(const std::string& text) {
        text_ = text;
    }
    const std::string& getText() const {
        return text_;
    }
    TextMemento createMemento() {
        return TextMemento(text_);
    }
    void restoreMemento(const TextMemento& memento) {
        text_ = memento.getText();
    }
private:
    std::string text_;
};

int main() {
    TextEditor editor;

    std::vector<TextMemento> history;

    editor.setText("Hello, World!");
    history.push_back(editor.createMemento());

    editor.setText("Goodbye!");
    history.push_back(editor.createMemento());
    std::cout << "Current Text: " << editor.getText() << std::endl;

    editor.restoreMemento(history[0]);
    std::cout << "After Undo: " << editor.getText() << std::endl;

    editor.restoreMemento(history[1]);
    std::cout << "After Redo: " << editor.getText() << std::endl;
    return 0;
}

运行结果:

bash 复制代码
Current Text: Goodbye!
After Undo: Hello, World!
After Redo: Goodbye!

七,参考阅读

https://softwarepatterns.com/cpp/memento-software-pattern-cpp-example

https://www.scaler.com/topics/memento-design-pattern/

https://sourcemaking.com/design_patterns/memento

https://www.geeksforgeeks.org/memento-design-pattern-c-design-patterns/

相关推荐
余辉zmh31 分钟前
【c++篇】:深入c++的set和map容器--掌握提升编程效率的利器
开发语言·c++
Labiod1 小时前
PlantUML 安装
linux·运维·服务器
·云扬·3 小时前
Java IO 与 BIO、NIO、AIO 详解
java·开发语言·笔记·学习·nio·1024程序员节
命里有定数3 小时前
Ubuntu问题 -- 设置ubuntu的IP为静态IP (图形化界面设置) 小白友好
linux·tcp/ip·ubuntu·ip
荆棘鸟骑士4 小时前
Linux修改/etc/hosts不起作用(ping: xxx: Name or service not known)的解决方法——开启NSCD
linux
东方巴黎~Sunsiny4 小时前
java-图算法
java·开发语言·算法
猫猫不是喵喵.4 小时前
【Linux】Linux入门实操——进程管理(重点)
linux·运维·服务器
小杨 学习日志5 小时前
C高级学习笔记
c语言·笔记·学习
DdddJMs__1355 小时前
C语言 | Leetcode C语言题解之第564题寻找最近的回文数
c语言·leetcode·题解
jackknight5 小时前
浪潮云启操作系统(InLinux) bcache宕机问题分析
linux