C++实现设计模式---备忘录模式 (Memento)

news/2025/1/17 3:06:11/

备忘录模式 (Memento)

备忘录模式 是一种行为型设计模式,它允许在不破坏封装的前提下,捕获和恢复对象的内部状态。通过备忘录模式,可以在程序运行时存储某个对象的历史状态,并在需要时恢复。


意图

  • 提供一种方法,在不破坏对象封装性的前提下捕获和恢复其内部状态。
  • 通过备忘录存储对象的历史状态,便于实现撤销、重做功能。

使用场景

  1. 需要保存对象的历史状态
    • 如文本编辑器中的撤销、恢复功能。
  2. 需要在程序运行时回滚对象状态
    • 如游戏中存储和恢复玩家进度。
  3. 希望避免暴露对象的实现细节
    • 通过备忘录隐藏对象的内部状态。

参与者角色

  1. 发起人 (Originator)
    • 定义一个创建和恢复备忘录的接口,负责存储对象的内部状态。
  2. 备忘录 (Memento)
    • 存储发起人对象的内部状态。
    • 对发起人以外的其他对象是不可变的。
  3. 管理者 (Caretaker)
    • 负责保存和恢复备忘录,但无法访问备忘录的内容。

示例代码

以下代码展示了备忘录模式的实现,用于模拟一个文本编辑器的撤销和恢复功能。

#include <iostream>
#include <string>
#include <vector>
#include <memory>// 备忘录类:存储文本状态
class Memento {
private:std::string state;public:explicit Memento(const std::string& state) : state(state) {}std::string getState() const {return state;}
};// 发起人类:文本编辑器
class TextEditor {
private:std::string text;public:void appendText(const std::string& newText) {text += newText;}void setText(const std::string& newText) {text = newText;}std::string getText() const {return text;}// 创建备忘录std::unique_ptr<Memento> save() const {return std::make_unique<Memento>(text);}// 恢复状态void restore(const Memento& memento) {text = memento.getState();}
};// 管理者类:管理备忘录
class Caretaker {
private:std::vector<std::unique_ptr<Memento>> history;public:void save(std::unique_ptr<Memento> memento) {history.push_back(std::move(memento));}const Memento* undo() {if (!history.empty()) {const Memento* memento = history.back().get();history.pop_back();return memento;}return nullptr;}
};// 客户端代码
int main() {TextEditor editor;Caretaker caretaker;editor.appendText("Hello");caretaker.save(editor.save()); // 保存状态editor.appendText(", World!");caretaker.save(editor.save()); // 保存状态editor.appendText(" Welcome to the Memento Pattern.");std::cout << "当前文本: " << editor.getText() << "
";// 撤销操作const Memento* memento = caretaker.undo();if (memento) {editor.restore(*memento);std::cout << "撤销后文本: " << editor.getText() << "
";}memento = caretaker.undo();if (memento) {editor.restore(*memento);std::cout << "再次撤销后文本: " << editor.getText() << "
";}return 0;
}

代码解析

1. 备忘录类 (Memento)
  • 存储发起人对象的内部状态,并提供一个方法获取状态。
  • 对其他对象不可变,只有发起人可以访问和修改它的内容。
class Memento {
private:std::string state;public:explicit Memento(const std::string& state) : state(state) {}std::string getState() const {return state;}
};
2. 发起人类 (TextEditor)
  • 负责创建和恢复备忘录。
  • 提供 save 方法创建备忘录和 restore 方法恢复备忘录中的状态。
class TextEditor {
private:std::string text;public:void appendText(const std::string& newText) {text += newText;}std::unique_ptr<Memento> save() const {return std::make_unique<Memento>(text);}void restore(const Memento& memento) {text = memento.getState();}
};
3. 管理者类 (Caretaker)
  • 保存和管理备忘录对象的历史。
  • 提供 save 方法保存备忘录,和 undo 方法实现状态回滚。
class Caretaker {
private:std::vector<std::unique_ptr<Memento>> history;public:void save(std::unique_ptr<Memento> memento) {history.push_back(std::move(memento));}const Memento* undo() {if (!history.empty()) {const Memento* memento = history.back().get();history.pop_back();return memento;}return nullptr;}
};
4. 客户端代码
  • 客户端通过 TextEditor 创建和恢复状态,Caretaker 保存备忘录。

优缺点

优点
  1. 封装性
    • 备忘录对象对其他类是不可变的,保护了发起人的内部状态。
  2. 简化撤销/恢复操作
    • 通过备忘录存储历史状态,可以轻松实现撤销和恢复功能。
  3. 符合单一职责原则
    • 发起人和管理者各自负责不同的功能。
缺点
  1. 内存开销
    • 每次保存状态都会创建一个备忘录对象,可能占用较多内存。
  2. 实现复杂性
    • 需要额外的类来管理和存储备忘录。

适用场景

  1. 需要存储对象的历史状态
    • 如撤销功能、版本控制等场景。
  2. 需要恢复对象状态
    • 如游戏进度存储和恢复。
  3. 希望对象状态的存储和恢复对外透明
    • 通过备忘录隐藏内部实现细节。

总结

备忘录模式通过存储对象的历史状态,实现了状态的保存和恢复功能。它特别适用于需要撤销操作或恢复特定状态的场景。虽然会增加内存开销,但其封装性和操作的便利性使其在许多应用中非常有用。


http://www.ppmy.cn/news/1563772.html

相关文章

ansible 检查目录大小

检查目录大小 worker_du.yml# ansible-playbook -i hosts worker_du.yml --limit w10 --- - name: 检查目录大小hosts:- w10 # 可以根据需要修改目标主机# 可以添加更多主机tasks:- name: 获取每台主机 /root/worker01 目录大小shell: du -sh /root/worker01/ | awk {print …

干货答疑分享记录:as导入问题,LSP含义,分屏进入SplashScreen

背景&#xff1a; vip学员群经常会有学员遇到一些常见的android framework开发问题&#xff0c;近期收集整理一些疑问&#xff0c;主要有以下3个&#xff1a; 1、android studio对源码进行导入时候&#xff0c;老是无法跳转到系统source code 2、学员在群里询问dumpOtherPro…

ChatGLM:从GLM-130B到GLM-4全系列大语言模型

摘要 我们介绍了ChatGLM&#xff0c;这是一个不断进化的大语言模型系列&#xff0c;我们一直在持续开发中。本报告主要聚焦于GLM-4语言系列&#xff0c;包括GLM-4、GLM-4-Air和GLM-4-9B。它们代表了我们从ChatGLM前三代中汲取的所有见解和经验教训所训练出的最强大模型。迄今为…

【DevOps】Jenkins配置钉钉邮件通知

Jenkins配置钉钉邮件通知 文章目录 Jenkins配置钉钉邮件通知介绍一、顶顶群机器人设置1.1、点击添加机器人 二、顶顶Webhook配置2.1、安装顶顶插件2.2、顶顶机器人配置 三、创建Pipeline项目(测试) 介绍 Jenkins作为最流行的开源持续集成平台&#xff0c;其强大的拓展功能一直…

【Python】使用python 对excel文件进行加密

最近在跟同事对接工作的时候&#xff0c;我需要把Excel文件发给对方。 但是由于文件内容的私密性&#xff0c;需要对Excel文件进行加密&#xff0c;保护文件以免给第三方看到&#xff0c;保障数据的安全。 在Python中&#xff0c;有多种方法可以对Excel文件进行加密。以下是几…

React Fiber框架中的Render渲染阶段——workLoop(performUnitOfWork【beginWork与completeWork】)

触发渲染过程——renderRoot renderRoot 是一个函数&#xff0c;用于触发渲染工作。它通常会调用并递归地执行一系列的渲染任务&#xff0c;直到完成整个更新过程。这个过程包括执行 Fiber 树中的 beginWork 和 completeWork&#xff0c;以及渲染新状态或 DOM。 function ren…

实用好软-----电脑端链接手机 免root权限管理手机 调试安卓

来自知名开发者开发。而且近期更新了全功能的搞机工具。对于链接电脑进行管理手机比较方便。新版重写了多线程逻辑&#xff0c;修复大量卡顿与无响应问题&#xff0c;同时优化了设备检测逻辑&#xff0c;启动更快更丝滑。还有大量新增免ROOT功能。对于玩机来说非常不错 由于AD…

MySQL数据库(SQL分类)

SQL分类 分类全称解释DDLData Definition Language数据定义语言&#xff0c;用来定义数据库对象&#xff08;数据库&#xff0c;表&#xff0c;字段&#xff09;DMLData Manipulation Language数据操作语言&#xff0c;用来对数据库表中的数据进行增删改DQLData Query Languag…