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/

相关推荐
小张成长计划..10 小时前
【Linux】10:冯·诺依曼体系结构和操作系统
linux·运维·服务器
喜欢的名字被抢了11 小时前
Python实战:SQLAlchemy ORM与FastAPI项目集成
开发语言·python·sql·教程·fastapi
从零开始的代码生活_13 小时前
C++ 内存管理:从内存分区到 new/delete 底层原理
开发语言·c++·后端
悦儿遥遥雨113 小时前
PXE + Kickstart 无人值守批量部署系统
linux·javascript·nginx
wabs66613 小时前
关于单调栈【力扣739.每日温度的思考】
java·开发语言
AOwhisky13 小时前
Python 学习笔记(第三期)——流程控制核心知识点自测与详解
开发语言·笔记·python·学习·云原生·运维开发·流程控制
Imagine Miracle14 小时前
【WSL】让WSL2后台持久运行不自动关闭的解决方案
linux·windows·wsl
aaPIXa62214 小时前
C++ 用 13 条规则让模型写出安全现代 C++
java·c++·安全
兔C14 小时前
Linux 命令行入门学习资料 day_2
linux·运维·服务器
逆向编程14 小时前
Socket异常连接自动清理方案
开发语言