设计模式(行为型)-备忘录模式

目录

定义

类图

角色

角色详解

(一)发起人角色(Originator)​

(二)备忘录角色(Memento)​

(三)备忘录管理员角色(Caretaker)​

优缺点

优点​

缺点​

使用场景

可回滚的操作场景​

游戏存档场景​

需要监控的副本场景​


定义

        备忘录模式,英文名为 Memento Pattern,是 GoF(Gang of Four,即设计模式领域的四位大师:Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides)提出的 23 种经典设计模式之一,属于行为型设计模式范畴。其核心定义为:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。如此一来,后续便能够将该对象恢复到先前保存的状态。​

        打个比方,我们在使用绘图软件时,可能会进行一系列的绘图操作,如绘制图形、填充颜色、调整线条粗细等。如果没有备忘录模式,一旦我们操作失误,比如不小心删除了重要图形或者对颜色填充不满意,可能就很难恢复到之前理想的状态。但有了备忘录模式,绘图软件就可以在每次关键操作前,将当前画布的状态(即对象的内部状态,包括绘制的图形、颜色设置、线条样式等)捕获并保存起来。当我们想要撤销操作时,软件就能从这些保存的状态中取出对应的状态,将画布恢复到之前的样子。

类图

角色

        备忘录模式的类图主要涉及三个核心角色,它们相互协作,共同实现了对象状态的保存与恢复功能。​

  • 发起人角色(Originator):这一角色在类图中处于核心地位,它就像是一个拥有自主记忆能力的个体。发起人角色负责记录当前时刻自身的内部状态,同时具备创建和恢复备忘录数据的关键能力。在代码实现层面,它通常会有一个方法用于创建备忘录,将自身当前的状态信息打包存储到备忘录对象中;另外还会有一个方法,当需要恢复状态时,从传入的备忘录对象中提取信息,恢复自身的状态。例如,在一个游戏角色类中,游戏角色就是发起人角色,它可以创建一个备忘录来记录自己当前的等级、生命值、装备等状态,也能够从一个已有的备忘录中读取这些信息,恢复到之前保存的状态。​

  • 备忘录管理员角色(Caretaker):可以把备忘录管理员角色看作是一个细心的图书管理员,它负责对备忘录进行管理,包括保存和提供备忘录。然而,它并不直接操作备忘录中的内容,仅仅起到一个中间协调和管理的作用。在类图中,它与备忘录角色和发起人角色都有一定的关联,它从发起人角色那里获取备忘录对象并妥善保存,当发起人角色需要恢复状态时,再将对应的备忘录对象提供给发起人角色。比如在游戏存档系统中,备忘录管理员角色可能会将游戏角色创建的备忘录(记录了游戏角色的各种状态)存储到硬盘的特定位置,当玩家需要读取存档恢复游戏角色状态时,它再从存储位置取出对应的备忘录提供给游戏角色(发起人角色)。

  • 备忘录角色(Memento):备忘录角色如同一个精心设计的容器,专门用于存储发起人角色的内部状态。为了确保封装性,它通常会对状态信息进行合理的封装,防止外部对象随意访问和修改。在类图中,备忘录角色与发起人角色紧密关联,发起人角色能够访问备忘录角色中存储的详细状态信息,而其他外部角色则只能看到备忘录角色提供的有限接口,无法直接窥探和篡改其中的状态数据。以绘图软件为例,备忘录角色可能会存储画布上所有图形的坐标、形状、颜色等详细信息,这些信息对于绘图软件的核心逻辑(发起人角色)来说是可访问的,以便在需要时进行状态恢复,但对于外部的普通用户操作接口来说,是不可见且不可随意修改的。​

角色详解

(一)发起人角色(Originator)​

  • 状态记录:发起人角色需要精确地记录自身当前时刻的内部状态。这要求它对自身的各个属性和状态有清晰的认知,并能够将这些信息以一种可存储的方式整理出来。例如,在一个财务记账系统中,记账本对象作为发起人角色,需要记录当前的账目余额、每一笔交易的明细(包括交易时间、金额、对方账户等)等内部状态信息。​

  • 备忘录创建:发起人角色拥有创建备忘录的能力,它将当前记录好的内部状态信息封装到一个备忘录对象中。这个过程就像是把一本书的所有内容整理好后放进一个文件袋里。在代码实现上,通常会创建一个备忘录类的实例,并将自身的状态信息赋值给备忘录类的相应属性。比如,在一个文本编辑器中,文本对象作为发起人角色,当需要创建备忘录时,它会将当前文本的内容、光标位置、字体设置等信息封装到一个备忘录对象中。​

  • 状态恢复:当需要恢复到之前保存的状态时,发起人角色能够从传入的备忘录对象中提取相应的状态信息,并将自身的状态恢复到备忘录所记录的状态。这就如同从文件袋中取出书,重新阅读并按照书中记录的内容调整自身状态。例如,在一个图形设计软件中,图形对象作为发起人角色,当接收到一个包含之前图形状态信息的备忘录对象时,它会读取备忘录中的图形形状、颜色、位置等信息,将自身的图形状态恢复到对应的样子。​

(二)备忘录角色(Memento)​

  • 状态存储:备忘录角色的主要职责就是安全、可靠地存储发起人角色的内部状态。它会根据发起人角色的状态信息结构,设计相应的属性来存储这些信息。例如,在一个游戏角色的备忘录中,会有属性来存储角色的等级、生命值、魔法值、背包物品清单等信息。这些属性通常会被设置为私有的,以保证状态信息的封装性,防止外部非法访问和修改。​

  • 访问控制:为了维护封装性,备忘录角色会对状态信息的访问进行严格控制。对于发起人角色,它提供足够的接口,使得发起人能够读取和设置状态信息,以便进行状态恢复操作。但对于其他外部角色,只提供非常有限的接口,甚至不提供任何接口,避免外部对象随意获取和篡改备忘录中的状态信息。比如,在一个数据库事务的备忘录中,只有数据库事务处理模块(发起人角色)能够直接访问备忘录中记录的事务状态、数据修改内容等信息,而其他无关的业务模块则无法直接访问这些敏感信息。​

(三)备忘录管理员角色(Caretaker)​

  • 备忘录保存:备忘录管理员角色负责接收发起人角色创建的备忘录对象,并将其妥善保存起来。保存的方式可以有多种,比如存储在内存中的数据结构里(如列表、栈等),或者存储到外部存储设备(如硬盘、数据库)中。在一个文档编辑软件中,当用户进行保存操作时,文档对象(发起人角色)创建一个备忘录记录当前文档的状态,备忘录管理员角色则将这个备忘录存储到硬盘上的特定文档版本管理目录中。​

  • 备忘录提供:当发起人角色需要恢复状态时,备忘录管理员角色能够准确地找到并提供相应的备忘录对象给发起人角色。这就要求备忘录管理员角色在保存备忘录时,有合理的索引和管理机制,以便能够快速定位到需要的备忘录。例如,在一个版本控制系统中,备忘录管理员角色会根据版本号等信息,将对应的备忘录提供给需要恢复到特定版本状态的文件对象(发起人角色)。

优缺点

优点​

  • 状态恢复机制:备忘录模式为用户提供了一种极为便捷的状态恢复机制。在许多应用场景中,用户可能会因为误操作或者想要尝试不同的操作路径,而需要回到之前的某个状态。例如在文档编辑过程中,用户可能不小心删除了重要段落,通过备忘录模式实现的撤销功能,就可以轻松恢复到删除前的状态;在图形设计中,对某个图形的操作不满意,也能利用备忘录模式回到操作前的状态。这种状态恢复机制极大地提高了用户体验,减少了用户因为错误操作而产生的焦虑和时间浪费。​

  • 信息封装性:通过将对象的内部状态封装在备忘录对象中,备忘录模式实现了良好的信息封装。外部对象无法直接访问和修改发起人对象的内部状态,只有发起人对象自身能够通过备忘录对象来管理和恢复自己的状态。这不仅提高了系统的安全性,防止了外部非法操作对对象内部状态的破坏,还使得系统的结构更加清晰,各模块之间的耦合度降低。例如,在一个企业资源规划(ERP)系统中,财务模块的内部状态(如账目余额、成本核算数据等)通过备忘录模式进行封装,其他业务模块无法直接访问和修改这些敏感信息,保证了财务数据的准确性和安全性。​

  • 简化发起人类:备忘录模式减轻了发起人类的负担,使其不再需要自行管理和保存自身内部状态的多个版本。在没有使用备忘录模式时,发起人类可能需要维护复杂的数据结构来记录自身的状态变化历史,这会增加代码的复杂性和维护成本。而采用备忘录模式后,发起人只需要专注于自身的核心业务逻辑,状态的保存和管理工作由备忘录角色和备忘录管理员角色来完成。比如,在一个游戏角色类中,原本可能需要在游戏角色类内部维护一个复杂的状态栈来记录每次升级、战斗后的状态变化,使用备忘录模式后,游戏角色类只需要在需要时创建和恢复备忘录,状态的存储和管理工作交给了备忘录和备忘录管理员。​

缺点​

  • 资源消耗问题:如果发起人角色的状态数据量较大,并且需要频繁地创建和保存备忘录,那么在资源消耗方面会面临较大压力。每个备忘录对象都需要占用一定的内存空间,如果长时间积累大量的备忘录,可能会导致内存不足等问题。例如,在一个大型 3D 建模软件中,模型对象的状态(包括复杂的几何形状、材质纹理、光照设置等)数据量巨大,每保存一次状态就会生成一个庞大的备忘录对象,如果用户频繁进行保存操作,会迅速消耗大量的内存资源。​

  • 存储容量不确定性:备忘录管理员角色在保存备忘录时,往往难以预先知道一个备忘录对象会占用多大的存储空间。这就可能导致在存储管理方面出现问题,比如在有限的硬盘空间中,可能因为不断保存备忘录而导致空间不足,但又无法提前提醒用户某个操作会产生较大的存储开销。例如,在一个手机游戏中,游戏存档(即备忘录)的大小可能会因为玩家在游戏中的不同行为(如收集大量物品、解锁复杂剧情等)而有很大差异,游戏开发者很难准确预估每个存档的大小,这可能会给玩家带来存储空间不足的困扰。​

  • 状态有效性问题:当发起人角色的状态发生改变时,新的状态并不一定总是有效的。在这种情况下,如果频繁使用备忘录模式进行状态恢复,可能会导致系统陷入一种混乱的状态。而且,如果状态改变的成功率较低,频繁地保存和恢复备忘录可能并不是一个高效的解决方案,不如采用其他更合适的设计模式,如 “假如” 协议模式(在执行操作前先假设操作成功,进行一系列模拟操作,若实际操作失败再进行回滚等处理)。例如,在一个金融交易系统中,每一笔交易操作都可能改变账户的状态,但交易过程中可能会因为各种原因(如网络故障、账户余额不足等)导致交易失败,如果频繁使用备忘录模式来恢复交易前的账户状态,可能会影响系统的稳定性和交易效率。

使用场景

可回滚的操作场景​

  • 文本编辑软件:像我们日常使用的 Word、WPS 等文本编辑软件,其中的撤销(Ctrl + Z)和重做(Ctrl + Y)功能就是备忘录模式的典型应用。在我们输入文字、修改格式、删除内容等操作过程中,文本编辑软件会在每次关键操作前创建一个备忘录,记录当前文档的状态。当我们按下撤销键时,软件就从之前保存的备忘录中取出对应的状态,将文档恢复到上一个操作前的状态;按下重做键时,则从后续保存的备忘录中获取状态,将文档恢复到撤销前的状态。​

游戏存档场景​

  • 游戏存档是备忘录模式最为人熟知的应用场景之一。在各种类型的游戏中,玩家在游戏过程中会不断改变游戏角色的状态(如等级提升、装备获取、任务进度推进等)。为了让玩家能够在后续继续游戏时从之前保存的进度开始,游戏系统会在玩家进行存档操作时,创建一个备忘录记录游戏角色的当前状态,包括角色的各项属性(生命值、魔法值、攻击力等)、背包中的物品、所处的游戏地图位置、完成的任务列表等信息。当玩家读取存档时,游戏系统从对应的备忘录中获取这些信息,将游戏角色恢复到存档时的状态,让玩家能够继续之前的游戏体验。例如,在一款大型角色扮演游戏中,玩家经过长时间的探索和战斗,到达了一个关键的游戏场景,此时玩家选择存档。之后,当玩家再次打开游戏读取存档时,游戏角色会以存档时的状态出现在之前的游戏场景中,玩家可以继续后续的游戏冒险。​

  • 综上所述,备忘录模式在软件开发的众多领域中都有着广泛而重要的应用,它为我们提供了一种强大的状态管理和恢复机制,虽然存在一些缺点,但在合适的场景下合理运用,能够显著提升系统的质量和用户体验。在实际的软件设计和开发过程中,我们需要根据具体的业务需求和系统特点,权衡利弊,决定是否采用备忘录模式来解决状态管理相关的问题。

  • 系统配置管理:在大型企业级系统中,系统配置的正确性对于系统的稳定运行至关重要。为了防止因为错误的配置修改导致系统故障,系统配置管理模块可以采用备忘录模式。在每次对系统配置进行修改前,创建一个备忘录记录当前的配置状态。如果修改后的配置导致系统出现问题,就可以从备忘录中恢复到之前正确的配置状态。比如,在一个云计算平台中,对服务器的网络配置、资源分配策略等进行修改时,利用备忘录模式可以保证在出现问题时能够快速回滚到稳定的配置状态。​

需要监控的副本场景​

  • 数据库事务管理:数据库事务是指作为单个逻辑工作单元执行的一系列操作,这些操作要么全部成功,要么全部失败。在数据库事务处理中,备忘录模式被广泛应用于事务的回滚操作。当开始一个事务时,数据库系统会创建一个备忘录,记录事务开始前数据库的状态(包括数据的版本、锁的状态等)。如果在事务执行过程中出现错误,系统就可以根据备忘录中的信息将数据库恢复到事务开始前的状态,保证数据的一致性和完整性。例如,在一个银行转账事务中,当从一个账户扣除金额并向另一个账户添加金额的过程中,如果出现网络故障等问题,就可以利用备忘录模式回滚事务,确保两个账户的金额不会出现错误的变动。​

  • 命令行操作:在操作系统的命令行界面中,有时我们可能会连续执行多个命令,当发现某个命令执行错误时,希望能够回滚到之前的系统状态。一些先进的命令行工具就采用了备忘录模式,记录每次命令执行前系统的关键状态(如文件系统状态、环境变量等),当用户执行撤销命令时,能够恢复到之前正确的状态。​

  • 图形设计软件:在 Adobe Photoshop、Sketch 等图形设计软件中,用户对图形的绘制、变形、颜色调整等操作都可以通过备忘录模式实现可回滚。比如,当我们对一个图层进行了复杂的滤镜处理后,发现效果不理想,就可以利用备忘录模式撤销滤镜操作,恢复图层原来的状态。这种可回滚操作极大地提高了图形设计的灵活性和创作效率,让设计师能够更加大胆地尝试各种设计思路。​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/34862.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Navicat如何查看密码

近期遇到需要将大部分已存储的navicat数据库转发给其他人,于是乎进行导出文件 奈何对方不用navicat,无法进行文件的导入从而导入链接 搜罗navicat的密码查看,大部分都为php代码解析 以下转载GitHub上看到的一个python代码解析的脚本 这里是对…

Matlab 四分之一车体车辆半主动悬架鲁棒控制

1、内容简介 略 Matlab 173-四分之一车体车辆半主动悬架鲁棒控制 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略

Python学习第十九天

Django-分页 后端分页 Django提供了Paginator类来实现后端分页。Paginator类可以将一个查询集(QuerySet)分成多个页面,每个页面包含指定数量的对象。 from django.shortcuts import render, redirect, get_object_or_404 from .models impo…

【大模型】Transformer、GPT1、GPT2、GPT3、BERT 的论文解析

前言 在自然语言处理(NLP)和深度学习的快速发展中,Transformer模型和 GPT系列模型扮演了至关重要的角色。本篇博客旨在对这些开创性的论文进行介绍,涵盖它们的提出时间、网络结构等关键信息,能够快速的理解这些模型的设…

【DeepSeek应用】本地部署deepseek模型后,如何在vscode中调用该模型进行代码撰写,检视和优化?

若已成功在本地部署了 DeepSeek 模型(例如通过 vscode-llm、ollama 或私有 API 服务),在 VS Code 中调用本地模型进行代码撰写、检视和优化的完整流程如下: 1. 准备工作:确认本地模型服务状态 模型服务类型: 若使用 HTTP API 服务(如 FastAPI/Flask 封装),假设服务地址…

【C语言】函数和数组实践与应用:开发简单的扫雷游戏

【C语言】函数和数组实践与应用:开发简单的扫雷游戏 1.扫雷游戏分析和设计1.1扫雷游戏的功能说明(游戏规则)1.2游戏的分析与设计1.2.1游戏的分析1.2.2 文件结构设计 2. 代码实现2.1 game.h文件2.2 game.c文件2.3 test.c文件 3. 游戏运行效果4…

需求分析、定义、验证、变更、跟踪(高软47)

系列文章目录 需求分析、定义、验证、变更、跟踪 文章目录 系列文章目录前言一、需求分析二、需求定义三、需求验证四、需求变更五、需求跟踪六、真题总结 前言 本节讲明需求分析、定义、验证、变更、跟踪相关知识。 一、需求分析 二、需求定义 三、需求验证 四、需求变更 五、…

【拒绝算法PUA】LeetCode 2270. 分割数组的方案数

系列文章目录 【拒绝算法PUA】0x00-位运算 【拒绝算法PUA】0x01- 区间比较技巧 【拒绝算法PUA】0x02- 区间合并技巧 【拒绝算法PUA】0x03 - LeetCode 排序类型刷题 【拒绝算法PUA】LeetCode每日一题系列刷题汇总-2025年持续刷新中 C刷题技巧总结: [温习C/C]0x04 刷…

uniapp 实现的步进指示器组件

采用 uniapp 实现的一款步进指示器组件,展示业务步骤进度等内容,对外提供“前进”、“后退”方法,让用户可高度自定义所需交互,适配 web、H5、微信小程序(其他平台小程序未测试过,可自行尝试) 可…

每日Attention学习26——Dynamic Weighted Feature Fusion

模块出处 [ACM MM 23] [link] [code] Efficient Parallel Multi-Scale Detail and Semantic Encoding Network for Lightweight Semantic Segmentation 模块名称 Dynamic Weighted Feature Fusion (DWFF) 模块作用 双级特征融合 模块结构 模块思想 我们提出了 DWFF 策略&am…

接上一篇,C++中,如何设计等价于Qt的信号与槽机制。

看下面例子: class FileManager : public QObject {Q_OBJECTpublic:FileManager(QObject* parent nullptr) : QObject(parent) {}void changeFileName(const QString& newName) {fileName newName;emit fileNameChanged(fileName);}signals:void fileNameChan…

上传本地项目到GitHub

一、在GitHub上创建仓库 1.点击右上角头像–>点击Your repositories 2.点击New 3.创建仓库 网址复制一下,在后面git上传时会用到 二、打开Git Bash 1.cd 进入项目所在路径 2.输入git init 在当前项目的目录中生成本地的git管理(当前目录下出现.…

基于Python的selenium入门超详细教程(第2章)--单元测试框架unittest

学习路线 自动化测试介绍及学习路线-CSDN博客 ​自动化测试之Web自动化(基于pythonselenium)-CSDN博客 基于Python的selenium入门超详细教程(第1章)--WebDriver API篇-CSDN博客 目录 前言: 一、单元测试 1. 单元测试的定义 2. 单元测…

HTML5 drag API实现列表拖拽排序

拖拽API(Drag and Drop API)是HTML5提供的一组功能,使得在网页上实现拖放操作变得更加简单和强大。这个API允许开发者为网页元素添加拖拽功能,用户可以通过鼠标将元素拖动并放置到指定的目标区域。 事件类型 dragstart&#xff1…

游戏引擎学习第163天

我们可以在资源处理器中使用库 因为我们的资源处理器并不是游戏的一部分,所以它可以使用库。我说过我不介意让它使用库,而我提到这个的原因是,今天我们确实有一个选择——可以使用库。 生成字体位图的两种方式:求助于 Windows 或…

Kafka可视化工具KafkaTool工具的使用

Kafka Tool工具 介绍 使用Kafka的小伙伴,有没有为无法直观地查看 Kafka 的 Topic 里的内容而发过愁呢?下面推荐给大家一款带有可视化页面的Kafka工具:Kafka Tool (目前最新版本是 3.0.2) 注意:以前叫Kafk…

在Spring Boot项目中接入DeepSeek深度求索,感觉笨笨的呢

文章目录 引言1. 什么是DeepSeek?2. 准备工作2.1 注册DeepSeek账号 3.实战演示3.1 application增加DS配置3.2 编写service3.3 编写controller3.4 编写前端界面chat.html3.5 测试 总结 引言 在当今快速发展的数据驱动时代,企业越来越重视数据的价值。为了…

【数据分析】读取文件

3. 读取指定列 针对只需要读取数据中的某一列或多列的情况,pd.read_csv()函数提供了一个参数:usecols,将包含对应的columns的列表传入该参数即可。 上面,我们学习了读取 "payment" 和 "items_count" 这…

Ubuntu 优化 Vim 指南

Vim 是一款功能强大的文本编辑器,通过合适的配置,可以变成一个接近 IDE 的高效开发工具。本指南提供 最精简、最实用 的 Vim 配置,满足 代码补全、语法高亮、代码格式化、目录管理等常用需求。 1. 必须安装的软件 首先,确保你的系…

信创环境下TOP5甘特图工具对比:从功能到适配性测评

在数字化转型的浪潮中,项目管理的高效与否直接决定了企业能否在激烈的市场竞争中脱颖而出。而甘特图作为项目管理中不可或缺的工具,其重要性不言而喻。尤其是在信创环境日益受到重视的当下,选择一款适配性强、功能完备的甘特图工具&#xff0…