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/

相关推荐
饮啦冰美式几秒前
22.04Ubuntu---ROS2使用rclcpp编写节点
linux·运维·ubuntu
wowocpp几秒前
ubuntu 22.04 server 安装 和 初始化 LTS
linux·运维·ubuntu
Huaqiwill2 分钟前
Ubuntun搭建并行计算环境
linux·云计算
wclass-zhengge5 分钟前
Netty篇(入门编程)
java·linux·服务器
Lign173146 分钟前
ubuntu unrar解压 中文文件名异常问题解决
linux·运维·ubuntu
童先生7 分钟前
Go 项目中实现类似 Java Shiro 的权限控制中间件?
开发语言·go
lulu_gh_yu8 分钟前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
Re.不晚32 分钟前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
老秦包你会34 分钟前
Qt第三课 ----------容器类控件
开发语言·qt
凤枭香37 分钟前
Python OpenCV 傅里叶变换
开发语言·图像处理·python·opencv