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

server/2024/9/23 14:23:53/

一,备忘录模式的定义

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

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

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

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

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

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

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

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

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

二,备忘录模式的结构

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

1.发起人(Originator):

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

2.备忘录(Memento):

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

3.管理者(Caretaker):

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

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

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

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

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

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

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

对应UML类图:

三,备忘录模式代码样例

Demo1:

#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;
}

运行结果:

Current state: State 3
Current state: State 3

Demo2:

#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;
}

运行结果:

Current state: 5
Current state: 10
Current state: 15
Current state: 20
Current state: 10

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

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

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

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

五,备忘录模式的优缺点

备忘录模式的优点:

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

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

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

备忘录模式的缺点:

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

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

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

六,代码实战

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

#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;
}

运行结果:

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/


http://www.ppmy.cn/server/117040.html

相关文章

pnpm解說

pnpm&#xff08;Performance Node Package Manager&#xff09;是一个高性能的Node.js包管理器&#xff0c;它旨在解决npm和yarn在处理依赖关系时可能遇到的一些问题&#xff0c;如重复安装相同版本的包、包的存储空间占用过大等。 pnpm使用了一种称为“硬链接”和“符号链接…

Linux:开源世界的璀璨明珠

一、Linux 概述 Linux 是一种自由和开放源代码的类 Unix 操作系统&#xff0c;诞生于 1991 年&#xff0c;由芬兰大学生 Linus Torvalds 开发。它的起源离不开 Unix 家族&#xff0c;1969 年肯・汤普森设计了早期 Unix 的源头&#xff0c;到 1973 年丹尼斯・里奇等人以 C 语言…

信息安全工程师(1)计算机网络分类

一、按分布范围分类 广域网&#xff08;WAN&#xff09;&#xff1a; 定义&#xff1a;广域网的任务是提供长距离通信&#xff0c;运送主机所发送的数据。其覆盖范围通常是直径为几十千米到几千千米的区域&#xff0c;因此也被称为远程网。特点&#xff1a;连接广域网的各个结点…

解锁生活密码,AI答案之书解决复杂难题

本文由 ChatMoney团队出品 介绍说明 “答案之书智能体”是您贴心的智慧伙伴&#xff0c;随时准备为您解答生活中的种种困惑。无论您在工作中遭遇瓶颈&#xff0c;还是在情感世界里迷失方向&#xff0c;亦或是对个人成长感到迷茫&#xff0c;它都能倾听您的心声&#xff0c;并给…

C++(2)之Linux多线程服务端编程总结

C之Linux多线程服务端编程读书笔记 Author: Once Day Date: 2023年1月31日/2024年8月23日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: Linux实践…

druid jdbc 执行 sql 输出 开销耗时

druid 执行sql输出 参考链接配置_LogFilter alibaba/druid Wiki GitHub 看不太懂的往这里瞅瞅。 1. 别名映射 这个地方 给我们提供了 5 种 logfilter : log4j、log4j2、slf4j、commonlogging和commonLogging 每一种实际上都代表一个日志框架 或 日志门面。 -Ddruid.fil…

【网络安全】-文件上传漏洞实战-upload-labs(0~16)

准备&#xff1a; 一句话木马&#xff1a;<? php eval($_REQUEST[cmd]); ?)> 格式&#xff1a;写入txt文本重命名后缀问.php /.php 格式&#xff0c;看具体要求上传。 Pass-01: 显示页面源代码&#xff0c;发现是js对不合法文件进行检查,上传修改为.jpg的php文件直接…

[网络][CISCO]CISCO_华为网络设备端口镜像配置

CISCO 华为网络设备端口镜像配置大全 isco交换机通常支持2组镜像&#xff0c;4000系列有支持6组镜象的。支持所全端口镜像。 Cisco catylist2820 有2个菜单选项 先进入menu选项&#xff0c;enable port monitor 进入cli模式&#xff0c; en conf term interface fast0/…