设计模式20-备忘录模式

news2024/9/22 17:36:31

设计模式20-备忘录

  • 动机
  • 定义与结构
    • 定义
    • 结构
  • C++代码推导
  • 优缺点
  • 应用场景
  • 总结
  • 备忘录模式和序列化
      • 备忘录模式
        • 1. **动机**
        • 2. **实现方式**
        • 3. **应用场景**
        • 4. **优点**
        • 5. **缺点**
      • 序列化
        • 1. **动机**
        • 2. **实现方式**
        • 3. **应用场景**
        • 4. **优点**
        • 5. **缺点**
      • 对比总结

动机

  • 在软件构建过程中,某些对象的状态在转换过程中可能由于某种需要这个程序能够回溯到对象之前处于某个点时的状态。使用一些公用接口来让其他对象得到对象的状态,便会暴露对象细节的实现
  • 如何实现对象状态的良好保存与恢复?但同时又不会因此而破坏对象本身的封装性呢。
  • 在软件开发中,有时需要在不破坏对象封装性的前提下捕获并存储对象的内部状态,以便稍后可以将对象恢复到以前的状态。这种需求通常出现在实现撤销/恢复操作的场景中,例如文本编辑器中的撤销操作。直接暴露对象的内部状态会违反封装原则,而备忘录模式提供了一种解决方案,使得状态恢复操作能够在不破坏封装性的前提下实现。

定义与结构

定义

备忘录模式在不破坏封装性的前提下,捕获对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。

结构

在这里插入图片描述

解释这张图

这张图描绘了一个典型的UML(统一建模语言)结构图,展示了“备忘录模式”(Memento Pattern)的核心组件及其关系。备忘录模式是一种用于捕获和存储一个对象内部状态的方式,以便可以在未来某个时刻将对象恢复到这个状态。这个模式特别适用于需要保存和恢复对象状态的场景,比如撤销操作、事务处理等。

图中包含了三个主要的类:

  1. Originator(原发器):这个类是需要被保存状态的对象。它包含一个CreateMemento()方法,用于创建一个备忘录对象(Memento),这个对象包含了Originator的当前状态。Originator还包含一个SetMemento(Memento m)方法,用于设置Originator的状态为备忘录对象(Memento)中存储的状态。图中对SetMemento方法的描述可能有些误解,因为通常这个方法不会直接从外部传入一个备忘录对象来设置状态,而是由Caretaker或者系统其他部分将之前保存的备忘录对象传递回Originator来恢复状态。

  2. Memento(备忘录):这个类用于存储Originator的内部状态,以保护这些状态不受外部访问。它包含了一个构造函数(尽管图中没有直接标出),该构造函数可能接受来自Originator的当前状态作为参数。Memento还包含GetState()SetState(state)方法(尽管图中SetState方法的参数可能标记有误,通常备忘录模式中的Memento类不需要SetState方法,因为备忘录主要是用来存储状态的)。但在实际实现中,GetState()方法用于返回备忘录中存储的状态,而SetState(如果存在的话)可能并不是Memento类的一部分,而是用于在Originator中恢复状态的过程中的一部分,但这通常是通过将Memento对象传递给Originator的某个恢复状态方法来实现的。

  3. Caretaker(管理者):这个类负责保存备忘录对象,但不检查备忘录对象的内容。在图中,Caretaker类被描述为有一个ReturnNewMemento(state)方法,这实际上可能是一个误解或错误。在标准的备忘录模式中,Caretaker类会维护一个备忘录对象的列表,但不直接创建新的Memento对象。相反,它可能包含一个AddMemento(Memento m)方法来添加新的备忘录对象,以及一个GetMemento(index)或类似的方法来检索之前保存的备忘录对象。图中的ReturnNewMemento(state)可能试图表达Caretaker返回一个新状态的Memento对象给Originator,但这并不是Caretaker类的典型职责;更常见的是,Caretaker简单地存储和检索Memento对象。

图中箭头表示类之间的交互关系。从Originator到Memento的箭头表示Originator创建Memento对象的过程,而从Caretaker到Originator的箭头(尽管图中没有直接画出)表示Caretaker可能将存储的Memento对象传递回Originator以恢复状态。

需要注意的是,图中的某些细节(如ReturnNewMemento(state)方法和SetState0方法的标记)可能与标准的备忘录模式实现不完全一致,可能是为了简化图示或特定实现的表示。

C++代码推导

以下是一个简单的备忘录模式的C++实现示例,模拟一个文本编辑器的撤销功能。

备忘录类:

#include <iostream>
#include <string>

// 备忘录类,用于存储Originator的内部状态
class Memento {
private:
    std::string state;

public:
    Memento(const std::string& state) : state(state) {}

    std::string getState() const {
        return state;
    }
};

发起人类:

class Originator {
private:
    std::string state;

public:
    void setState(const std::string& state) {
        this->state = state;
        std::cout << "State set to: " << state << std::endl;
    }

    std::string getState() const {
        return state;
    }

    Memento* createMemento() {
        return new Memento(state);
    }

    void setMemento(Memento* memento) {
        state = memento->getState();
        std::cout << "State restored to: " << state << std::endl;
    }
};

负责人类:

class Caretaker {
private:
    Memento* memento;

public:
    void saveMemento(Memento* memento) {
        this->memento = memento;
    }

    Memento* getMemento() {
        return memento;
    }

    ~Caretaker() {
        delete memento;
    }
};

客户端代码:

int main() {
    Originator* originator = new Originator();
    Caretaker* caretaker = new Caretaker();

    originator->setState("State1");
    caretaker->saveMemento(originator->createMemento());

    originator->setState("State2");
    caretaker->saveMemento(originator->createMemento());

    originator->setState("State3");

    // 恢复到上一个状态
    originator->setMemento(caretaker->getMemento());

    delete originator;
    delete caretaker;

    return 0;
}

运行结果:

State set to: State1
State set to: State2
State set to: State3
State restored to: State2

优缺点

优点:

  1. 封装性:备忘录模式可以在不破坏对象封装性的前提下保存和恢复对象的状态,符合对象的封装原则。
  2. 简化撤销操作:备忘录模式简化了复杂系统中的撤销操作实现,使得对象能够恢复到先前的状态。

缺点:

  1. 内存开销:如果对象的状态较大且备忘录创建频繁,可能会占用大量内存,增加系统开销。
  2. 管理复杂性:备忘录需要被妥善管理,尤其是在需要多个备忘录进行多步撤销时,备忘录的管理和恢复可能会变得复杂。

应用场景

备忘录模式在以下场景中应用较多:

  1. 需要保存对象状态以便恢复:例如实现多步撤销/恢复功能的场景,如文本编辑器、图形编辑器等。
  2. 需要避免暴露对象内部状态:当需要避免外部直接访问对象的内部状态时,可以使用备忘录模式来实现状态保存和恢复。
  3. 对象状态变化复杂且不可预测:在对象状态变化频繁且不可预测的情况下,备忘录模式可以有效管理这些状态变化。

总结

  • 备忘录模式是一种强大的设计模式,通过封装对象的内部状态,实现了状态的保存和恢复功能。虽然它能够有效地支持撤销和恢复操作,但在实际应用中需要注意内存消耗和管理复杂性,特别是在对象状态复杂且变化频繁的场景下。
  • 备忘录模式存储原发器对象的内部状态。在需要时恢复原发器状态。
  • 备忘录模式的核心是信息隐藏,即原发器需要向外界隐藏信息保持其封装性,但同时又需要将再保存到外界。
  • 由于现代语言运行时如JAVA ,c#,都具有相当的对象序列化支持。因此往往采用效率较高,又较容易正确实现的序列化方案来实现备忘录模式。

备忘录模式和序列化

备忘录模式和序列化在某些方面具有相似的功能,但它们的目标和应用场景不同。

备忘录模式

1. 动机

备忘录模式的主要动机是保存和恢复对象的内部状态,而不破坏对象的封装性。它常用于实现撤销/恢复操作,让对象能够恢复到之前的某个状态。

2. 实现方式

备忘录模式通过创建一个“备忘录”对象,将发起人(Originator)对象的内部状态存储在该备忘录对象中。发起人可以使用这个备忘录对象来恢复其内部状态。备忘录模式通常包括三个角色:发起人、备忘录和负责人(Caretaker),其中负责人仅负责管理备忘录的保存和恢复,不直接访问备忘录的内容。

3. 应用场景
  • 撤销/恢复操作:如文本编辑器、图形编辑器中的撤销功能。
  • 历史记录管理:需要保存对象的状态以便以后恢复。
  • 避免对象内部状态暴露:需要保存和恢复对象状态时,但不希望暴露对象的内部实现。
4. 优点
  • 封装性:备忘录模式可以在不破坏对象封装性的前提下保存和恢复状态。
  • 简单性:对外界来说,状态的保存和恢复过程是透明的,简化了撤销/恢复功能的实现。
5. 缺点
  • 内存消耗:如果对象的状态较大或备忘录频繁创建,可能会导致较大的内存开销。
  • 管理复杂性:当涉及多个状态备忘录时,备忘录的管理可能会变得复杂。

序列化

1. 动机

序列化的主要目的是将对象的状态转换为字节流,以便可以将其存储在文件、数据库或通过网络传输,并在以后将其反序列化为原始对象。

2. 实现方式

序列化将对象的状态转换为字节流,并将其保存到存储介质中。反序列化则是将字节流重新转换为对象。序列化通常依赖于语言或平台提供的内置机制,如Java的Serializable接口或C++的自定义序列化逻辑。

3. 应用场景
  • 持久化存储:将对象状态保存到文件或数据库中,以便以后恢复。
  • 网络传输:在分布式系统中,将对象状态通过网络传输到另一个系统。
  • 跨平台数据交换:不同平台之间的数据交换,需要将对象状态转换为通用的字节流格式。
4. 优点
  • 持久性:序列化使得对象状态可以长期保存,并在需要时恢复。
  • 跨平台:序列化后的数据可以在不同平台或系统之间传输和共享。
5. 缺点
  • 性能开销:序列化和反序列化可能会引入性能开销,特别是在大型对象或频繁操作的情况下。
  • 安全性:序列化数据可能会暴露对象的内部状态,存在安全风险,如果反序列化的对象来自不可信的来源,可能会导致安全漏洞。

对比总结

  1. 用途不同

    • 备忘录模式:主要用于保存和恢复对象的状态,以支持撤销/恢复操作,强调对象的封装性。
    • 序列化:主要用于持久化或跨网络传输对象的状态,强调对象的持久性和可传输性。
  2. 实现方式不同

    • 备忘录模式:通常是在内存中保存对象的状态,并通过备忘录对象管理状态的保存和恢复。
    • 序列化:将对象的状态转换为字节流,存储在外部介质中或通过网络传输。
  3. 封装性

    • 备忘录模式:注重保持对象的封装性,外部系统无法访问对象的内部状态。
    • 序列化:通常会暴露对象的内部状态,可能会引发安全问题。
  4. 应用场景不同

    • 备忘录模式:适用于需要频繁保存和恢复对象状态的场景,如撤销功能。
    • 序列化:适用于对象的持久化存储、网络传输、跨平台数据交换等场景。

备忘录模式更适合在应用程序内部管理对象的状态转换,而序列化更适合在应用程序与外部系统之间交换或持久化数据。两者可以结合使用,例如在分布式系统中,备忘录模式管理对象状态,而序列化用于将状态持久化或传输到其他节点。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis相关面试题(二)

一、BIT中不同命令使用的场景 Sring Seesion会话业务缓存分布式锁&#xff1a;为了防止用户同时登录多个设备进行操作 Int 计数器限流全局唯一ID Hash 电商购物车 BitMap 用户签到 List 消息队列 ZSet 排行榜 二、什么是缓存击穿&#xff0c;缓存穿透&#xff0c;…

C++--类和对象(一)

C是一个面向对象的编程语言&#xff0c;而面向对象编程有四大特性&#xff1a;封装&#xff0c;抽象&#xff0c;继承&#xff0c;多态。类和对象就是对应其中的封装&#xff0c;在C中将数据和对数据的操作都封装在一个class&#xff08;类&#xff09;的结构体中。 目录 类的…

【C++二分查找】2187. 完成旅途的最少时间

本文涉及的基础知识点 C二分查找 LeetCode2187. 完成旅途的最少时间 给你一个数组 time &#xff0c;其中 time[i] 表示第 i 辆公交车完成 一趟旅途 所需要花费的时间。 每辆公交车可以 连续 完成多趟旅途&#xff0c;也就是说&#xff0c;一辆公交车当前旅途完成后&#xf…

TCP如何建立长连接

文章目录 TCP建立长连接长连接和短连接长连接的优势TCP KEEPALIVE 心跳包心跳检测步骤 断线重连断线重连函数实现 实例服务端客户端程序功能演示效果 TCP建立长连接 长连接和短连接 长连接是指不论TCP的客户端和服务器之间是否有数据传输&#xff0c;都保持建立的TCP连接&…

Docker最佳实践(三):安装mysql

大家好&#xff0c;欢迎各位工友。 本篇呢我们就来演示一下如何在Docker中部署MySQL容器&#xff0c;可以按照以下步骤进行&#xff1a; 1. 搜索镜像 首先搜索MySQL镜像&#xff0c;可以使用以下命令&#xff1a; docker search mysql2. 拉取镜像 根据需求选择MySQL或Maria…

Oracle|DM 常用|不常用 SQL大口袋

目录 一、前言 二、SQL写法 1、sql获取某一条数据中的前一条和后一条 2、实现like多个值的查询&#xff08;Oracle和dm支持&#xff0c;MySQL未试过&#xff09; 3、start with connect by prior 使用方法 4、用hextoraw解决select、update、delete语句执行慢 5、ORA-00…

叉车数字化安全管理平台,安全管控升级,打造智慧监管新模式

近年来&#xff0c;国家和各地政府相继出台了多项政策法规&#xff0c;从政策层面推行叉车智慧监管&#xff0c;加大叉车安全监管力度。同时鼓励各地结合实际&#xff0c;积极探索智慧叉车建设&#xff0c;实现作业人员资格认证、车辆状态认证、安全操作提醒、行驶轨迹监控等&a…

场外个股期权的投资技巧:把握机遇与风险平衡

【来源&#xff1a;期权圈&#xff0c;场外个股每日询价】 在金融投资的领域中&#xff0c;场外个股期权作为一种新兴且具有吸引力的投资工具&#xff0c;为投资者提供了独特的机会和挑战。掌握有效的投资技巧&#xff0c;对于在这个领域中取得成功至关重要。 首先&#xff0c…

C++ | Leetcode C++题解之第332题重新安排行程

题目&#xff1a; 题解&#xff1a; class Solution { public:unordered_map<string, priority_queue<string, vector<string>, std::greater<string>>> vec;vector<string> stk;void dfs(const string& curr) {while (vec.count(curr) &am…

How we design Kola

How we design Kola - ApiHugKola background, Kola a consumer driver tester frameworkhttps://apihug.com/zhCN-docs/kola/002_design_of_kola Kola background, Kola a consumer driver tester framework ​BDD 行为驱动开发(BDD)是一种软件团队工作方式,可以缩小业务人…

基于STM32F429移植UCOSIII

μC/OS-III&#xff08;Micro C OS Three&#xff09;是一个可升级的、可固化的、基于优先级的实时内核&#xff0c;它是Micrium公司出品的RTOS&#xff08;实时操作系统&#xff09;类实时操作系统的一个版本。以下是对μC/OS-III的详细描述&#xff1a; 1. 基本特性 多任务管…

智能制造与工业互联网有何关联?工业互联网如何推进智能制造?

随着信息技术的飞速发展&#xff0c;智能制造和工业互联网已经成为当今产业变革的核心。智能制造&#xff0c;以其深度融合的设计、生产、管理、营销和售后服务等环节&#xff0c;代表了先进制造模式的典范。而工业互联网则作为智能制造的神经中枢&#xff0c;通过连接机器、人…

【初阶数据结构题目】17.用栈实现队列

用栈实现队列 点击链接答题 思路&#xff1a; 定义两个栈&#xff1a;pushST&#xff08;入数据&#xff09;和popST&#xff08;出数据&#xff09; 假设我们要在队列里放123&#xff0c;出队列123 我们先在pushST里面放进去1 2 3 然后把pushST里面的数据拿到popST里面&#…

会务要闻|向绿提质:上市企业ESG评级提升

在全球市场对环境、社会和治理&#xff08;ESG&#xff09;指标的关注与日俱增的大背景下&#xff0c;中国正积极拥抱ESG理念&#xff0c;将其作为推动经济与社会全面绿色转型的催化剂&#xff0c;更被企业视为长期主义投资策略的基石。面对日益严格的国际ESG尽职调查要求&…

信息论在机器学习中的实际应用

目录 一、说明 二、什么是信息论&#xff1f; 2.1 信息论中的关键概念 2.2 熵与信息 2.3 相互信息 2.4 Kullback-Leibler 背离 三、信息论在机器学习中的应用 3.1 功能选择&#xff1a; 3.2 计算边际概率分布 3.3 决策树&#xff1a;Information 增益 3.4 评估具有 KL 背…

FastAPI+Vue3工程项目管理系统项目实战私教课 上课笔记20240808 课程和学习计划制定

学习目标 将Word和Excel做的东西放到数据库里面去工程类公司&#xff0c;甲方&#xff0c;劳务存到数据库存储的信息主要是人员的信息 基本信息&#xff1a; 人员信息&#xff0c;资料库&#xff0c;甲方的人出现在哪些项目上&#xff0c;考勤材料信息&#xff0c;进货记录&…

yolov5更换主干网络shufflent

目录 1.网络结构解析 1.1创建yolov5s_shufflent_v2_X0_5.yaml文件 2.对common.py末尾进行添加 3.修改yolo.py 1.网络结构解析 1.可以先看看shufflenet_v2的网络结构 import torch from torch import nn from torchvision import models from torchinfo import summaryclas…

利用vscode-icons-js在Vue3项目中实现文件图标展示

背景&#xff1a; 在开发文件管理系统或类似的项目时&#xff0c;我们常常需要根据文件类型展示对应的文件图标&#xff0c;这样可以提高用户体验。本文将介绍如何在Vue3项目中利用vscode-icons-js库&#xff0c;实现类似VSCode的文件图标展示效果。 先看效果&#xff1a; 一…

Flink任务提交流程和运行模式

任务提交流程 Flink 的提交流程随着部署模式、资源管理平台的不同&#xff0c;会有不同的变化。这里做进一步的抽象&#xff0c;形成一个大概高视角的任务执行流程图&#xff0c;如下&#xff1a; Flink按照集群和资源管理的划分运行模式有&#xff1a;Standalone、Flink On…

你是否陷入了惯性思维的陷阱?

如何突破惯性思维&#xff1f; 文 / 周妙錥&#xff08;MEOW EE CHEW&#xff09;13-02-2024 什么是惯性思维&#xff1f; 惯性思维&#xff08;Inertial Thinking&#xff09;是指我们在面对问题、决策或行为选择时&#xff0c;倾向于依赖过去的经验、习惯或想法&#xff0…