实战设计模式之备忘录模式

news2025/5/9 18:38:16

概述

        与解释器模式、迭代器模式一样,备忘录模式也是一种行为设计模式。备忘录模式允许我们保存一个对象的状态,并在稍后恢复到这个状态。该模式非常适合于需要回滚、撤销或历史记录等功能的应用场景。通过使用备忘录模式,开发者可以轻松添加诸如撤销/重做、快照等高级功能,提升用户体验。

        文本编辑器的撤销/重做功能是运用备忘录模式最典型的应用场景。当我们在文本编辑器中输入或修改内容时,编辑器会定期创建当前文档状态的“快照”,即备忘录。如果我们需要撤销最近的操作,编辑器可以从这些快照中恢复到之前的状态。类似地,重做操作也可以通过管理一系列的备忘录来实现。这使得用户可以轻松地回退或前进到任意一个历史版本,而不需要担心数据丢失。

基本原理

        备忘录模式的基本原理可以概括为:创建一个独立的对象(备忘录),用于存储另一个对象(发起人)的内部状态。发起人在需要的时候可以请求创建一个备忘录,并将自身状态保存到这个备忘录中。同时,发起人也能够从备忘录中恢复状态。为了确保备忘录的安全性,通常会有一个管理者角色负责保管这些备忘录,但不允许对其进行任何操作。

        备忘录模式主要由以下三个核心组件构成。

        1、发起人。其职责包括创建备忘录以保存其内部状态,并通过备忘录来恢复其内部状态。发起人的状态通常是私有的,以保证数据的安全性和封装性。

        2、备忘录。这是一个用来存储发起人对象内部状态的对象。备忘录的设计目的是:保护发起人的内部状态不被其他对象访问或篡改。因此,备忘录通常只允许发起人和管理者对其进行读取或写入操作,而禁止其他对象对它进行任何形式的修改。

        3、管理者。管理者负责管理备忘录对象,但不对备忘录的内容进行任何操作。它的主要任务是保管备忘录对象,并在发起人需要恢复状态时提供相应的备忘录。管理者与备忘录之间的交互非常有限,这有助于保持系统的简洁性和模块化。

        基于上面的核心组件,备忘录模式的实现主要有以下四个步骤。

        1、定义发起人类。该类应包含一些方法来获取和设置其内部状态。此外,还需实现两个关键方法:CreateMemento和RestoreFromMemento。CreateMemento方法用于创建一个新的备忘录对象,并将当前状态保存到其中。RestoreFromMemento方法接收一个备忘录对象作为参数,并从中恢复发起人的状态。

        2、定义备忘录类。该类仅需简单地存储发起人的状态即可。由于备忘录的主要目的是保护发起人的状态,因此它不应该公开任何修改状态的方法,仅提供必要的访问方法供发起人使用。

        3、定义管理者类。该类负责保存和管理多个备忘录对象。管理者不需要知道备忘录的具体内容,只需要能够保存它们,并在需要时提供给发起人。管理者应当提供添加备忘录、获取特定备忘录的方法。

        4、使用备忘录模式。当发起人需要保存状态时,调用CreateMemento方法并将返回的备忘录交给管理者保存。如果需要恢复状态,则从管理者那里获取对应的备忘录,并调用RestoreFromMemento方法。

实战代码

        在下面的实战代码中,我们使用备忘录模式模拟了文本编辑器的撤销/重做功能。

        首先,我们定义了备忘录类CTextMemento。它用于存储文本编辑器的状态,即当前文本内容。CTextMemento有一个私有成员变量m_strContent用来保存文本内容,并提供了一个公共方法GetContent来获取该文本内容。

        接下来,我们定义了管理者类CHistoryManager。作为管理者角色,它负责管理备忘录对象。它包含两个向量:m_vctUndo和m_vctRedo,分别用于存储撤销栈和重做栈。SaveState方法用于将当前状态保存到撤销栈中。ClearRedoStack方法用于在进行新操作前清空重做栈,确保后续操作不会混淆历史记录。Undo方法用于从撤销栈弹出最近的状态并将其推入重做栈,然后返回新的当前状态。Redo方法则相反,从重做栈恢复状态,并将状态重新添加到撤销栈。

        然后,我们定义了发起人类CTextEditor。作为发起人角色,它代表了文本编辑器本身。它拥有一个成员变量m_strContent来保存实际的文本内容,并且持有一个HistoryManager实例m_manager来管理其状态的历史记录。Type方法允许用户输入新的文本,并保存新文本到m_manager中。Undo和Redo方法分别调用m_manager.Undo和m_manager.Redo来执行撤销和重做操作,并更新当前文本内容。

        最后,在main函数中,我们模拟了文本编辑器的行为,包括:输入文本、撤销和重做操作。

#include <iostream>
#include <vector>
#include <string>

using namespace std;

// 备忘录类,用于存储文本编辑器的状态
class CTextMemento
{
public:
    CTextMemento(const string& strContent) : m_strContent(strContent) {}

    string GetContent() const
    {
        return m_strContent;
    }

private:
    string m_strContent;
};

// 管理者类,用于管理备忘录对象
class CHistoryManager
{
public:
    void SaveState(const CTextMemento& memento)
    {
        m_vctUndo.push_back(memento);
    }

    void ClearRedoStack()
    {
        m_vctRedo.clear();
    }

    CTextMemento Undo()
    {
        if (!m_vctUndo.empty())
        {
            CTextMemento memento = m_vctUndo.back();
            m_vctUndo.pop_back();
            m_vctRedo.push_back(memento);
            if (!m_vctUndo.empty())
            {
                return m_vctUndo.back();
            }
        }

        return CTextMemento("");
    }

    CTextMemento Redo()
    {
        if (!m_vctRedo.empty())
        {
            CTextMemento memento = m_vctRedo.back();
            m_vctRedo.pop_back();
            m_vctUndo.push_back(memento);
            return memento;
        }

        return CTextMemento("");
    }

private:
    vector<CTextMemento> m_vctUndo;
    vector<CTextMemento> m_vctRedo;
};

// 发起人类,即文本编辑器
class CTextEditor
{
    // 允许HistoryManager访问TextEditor的内容
    friend class CHistoryManager;

public:
    void Type(const string& text)
    {
        // 清空重做栈
        m_manager.ClearRedoStack();
        m_strContent += text;
        m_manager.SaveState(CTextMemento(m_strContent));
        cout << "Typed: " << text << endl;
    }

    void Undo()
    {
        CTextMemento memento = m_manager.Undo();
        m_strContent = memento.GetContent();
        cout << "Undo to: " << m_strContent << endl;
    }

    void Redo()
    {
        CTextMemento memento = m_manager.Redo();
        m_strContent = memento.GetContent();
        cout << "Redo to: " << m_strContent << endl;
    }

    friend ostream& operator<<(ostream& os, const CTextEditor& editor)
    {
        os << "Current Content: " << editor.m_strContent;
        return os;
    }

private:
    CHistoryManager m_manager;
    string m_strContent;
};

int main()
{
    CTextEditor editor;

    editor.Type("Hello");
    cout << editor << endl;

    editor.Type(", Hope_Wisdom");
    cout << editor << endl;

    editor.Undo();
    cout << editor << endl;

    editor.Undo();
    cout << editor << endl;

    editor.Redo();
    cout << editor << endl;

    editor.Redo();
    cout << editor << endl;
    return 0;
}

总结

        备忘录模式允许对象保存其内部状态而不暴露其实现细节,这意味着,发起人可以安全地存储和恢复其状态,而无需担心破坏封装性或泄露敏感信息。对于拥有复杂内部状态的对象,备忘录模式提供了一种有效的方式来捕获和恢复这些状态,这对于需要长期运行的任务或处理大量数据的应用程序特别有用。

        但创建和保存大量的备忘录可能会占用较多内存资源,尤其是在处理大规模数据或长时间运行的任务时。如果频繁地创建备忘录,可能导致性能问题和内存溢出的风险。虽然备忘录模式本身的概念很简单,但在实际应用中,特别是在并发环境或多线程场景下,正确实现和管理备忘录可能会变得相当复杂。确保不同线程间备忘录的一致性和同步性,是一个比较大的挑战。

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

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

相关文章

吉尔吉斯斯坦工商会代表团赴齐河德瑞新能源汽车考察

德州齐河&#xff0c;2025年4月15日电 时中美贸易突变之际&#xff0c;乘国家一带一路之风。 展中国新能源之宏图&#xff0c;塑国贸体系之新方向。 今日上午&#xff0c;吉尔吉斯斯坦共和国工商会代表团一行三人受邀抵达济南&#xff0c;开启对德瑞新能源科技有限公司&…

无人机在农业中的应用与挑战!

一、无人机在农业中的作用 1. 提升作业效率与降低成本 无人机在喷洒农药、播种、施肥、吊运等环节显著提升效率。例如&#xff0c;湖北秭归县使用大疆T100无人机吊运脐橙&#xff0c;单次85公斤的运输任务仅需2分钟&#xff0c;而人工需1小时&#xff0c;综合成本降低250元…

QT网络拓扑图绘制实验

前言 在网络通讯中&#xff0c;我qt常用的是TCP或者UDP协议&#xff0c;就比方说TCP吧&#xff0c;一台服务器有时可能会和多台客户端相连接&#xff0c;我之前都是处理单链接情况&#xff0c;最近研究图结构的时候&#xff0c;突然就想到了这个问题。那么如何解决这个问题呢&…

支持中文对齐的命令行表格打印python库——tableprint

文章目录 快速入门 还在为表格中含有中文&#xff0c;命令行打印无法对齐而苦恼吗&#xff1f; 还在为冗长的数据添加代码而抓狂吗&#xff1f; tableprint来了&#xff01;&#xff01;&#xff01;&#xff0c;它完美的解决了上述两个问题&#xff0c;快来试试吧&#xff01;…

从《周游记3》演绎歌剧版《菊花台》,周杰伦婚礼曲目意大利文版惊喜亮相

今天&#xff08;4月19日&#xff09;22:00&#xff0c;由魔胴西西里咖啡冠名的户外实境互动综艺《周游记3》第四期即将播出。本期节目中&#xff0c;“J式之旅”发起人周杰伦和林暐恒、杜国璋、陈冠霖、陈冠廷&#xff0c;将继续意大利之旅&#xff0c;从那不勒斯的百年老店到…

生物化学笔记:医学免疫学原理23 免疫检查点分子与肿瘤免疫治疗(PD-1抑制剂黑色素瘤)

免疫检查点分子与肿瘤免疫治疗 免疫检查点分子与肿瘤免疫治疗-2

CasualLanguage Model和Seq2Seq模型的区别

**问题1&#xff1a;**Causal Language Modeling 和 Conditional Generation 、Sequence Classification 的区别是什么&#xff1f; 因果语言模型(Causal Language Model)&#xff1a; 预测给定文本序列中的下一个字符&#xff0c;一般用于文本生成、补全句子等&#xff0c;模型…

verilog float mult

module pipe_float_mul(input wire clk ,// 时钟信号input wire en ,// 使能信号input wire rst_n ,// 复位信号input wire round_cfg ,// 决…

微信小程序调用yolo目标检测模型

目录 后端 前端微信小程序 完整代码 后端 利用Flask&#xff0c;调用目标检测模型&#xff0c;后端代码如下。 # flask_yolo.py from flask import Flask, request, jsonify from ultralytics import YOLO from PIL import Imageapp Flask(__name__) model_path best.p…

Flink框架十大应用场景

Flink框架适合应用的场景 1. 流式数据处理 Flink框架最常用的应用场景是流式数据处理。流式数据处理是指对实时数据进行处理,以便及时地做出决策。例如,一个电商网站需要对用户的行为进行实时分析,以便根据用户的兴趣和行为推荐商品。Flink框架可以帮助电商网站实时地处理数…

【android telecom 框架分析 01】【基本介绍 2】【BluetoothPhoneService为何没有源码实现】

1. 背景 我们会在很多资料上看到 BluetoothPhoneService 类&#xff0c;但是我们在实际 aosp 中确找不到具体的实现&#xff0c; 这是为何&#xff1f; 这是一个很好的问题&#xff01;虽然在车载蓝牙电话场景中我们经常提到类似 BluetoothPhoneService 的概念&#xff0c;但…

【Harmony】文本公共接口EditMenuOptions的使用

文章目录 一、EditMenuOptions介绍二、相关接口介绍2.1、editMenuOptions2.2、EditMenuOptionsonCreateMenu函数说明onMenuItemClick函数说明 2.3、TextRange对象说明2.4、TextMenuItem对象说明2.5、TextMenuItemId属性ofequals 三、简单案例 一、EditMenuOptions介绍 EditMen…

《软件设计师》复习笔记(14.1)——面向对象基本概念、分析设计测试

目录 一、面向对象基本概念 对象&#xff08;Object&#xff09; 类&#xff08;Class&#xff09; 抽象&#xff08;Abstraction&#xff09; 封装&#xff08;Encapsulation&#xff09; 继承&#xff08;Inheritance&#xff09; 多态&#xff08;Polymorphism&#…

JS中实现类似sleep、wait、delay的延时功能

前言 编写代码时很多时候需要进行流程化的操作&#xff0c;各个流程间通常需要等待一定时间&#xff0c;这在很多语言中通常可以使用 sleep 、 wait 、 delay 等函数来实现。JavaScript原生并没有类似的功能&#xff0c;想要延时通常就是使用 setTimeout(functionRef, delay) …

Banana Pi BPI-RV2 RISC-V 路由器开发板发售, 全球首款RISC-V路由器

Banana Pi BPI-RV2 开源路由器是矽昌通信和⾹蕉派开源社区&#xff08;Banana Pi &#xff09;合作设计, 联合打造全球首款RISC-V架构路由器开发板。 这是香蕉派开源社区与矽昌通信继BPI-Wifi5 低成本Wifi5 路由器合作之后的又一力作&#xff0c;为全球开发者与商业客户提供基于…

MAUI项目iOS应用以进 App Store 分发

目录 一.通过Visual Studio分发应用1. 登录Apple 开发者帐户到 Visual Studio2.创建分发证书和配置文件3. 分发应用4. 在App Store Connect 中创建应用程序记录5. 如果你想使用mac发布应用 一.通过Visual Studio分发应用 1. 登录Apple 开发者帐户到 Visual Studio 首先我们要…

CentOS 7系统yum报错解决方案(CentOS 7官方EOL问题修复)

摘要 解决CentOS 7因EOL导致的yum update报错问题&#xff0c;通过替换阿里云镜像源恢复软件安装功能&#xff0c;包含详细操作步骤、操作截图、验证方法与备选镜像源&#xff0c;附有安全风险提示。 一、故障现象与原因分析 1.1 典型报错信息 # 执行yum命令时出现&#xff…

解决Windows update服务启动拒绝访问的问题 | wuauserv 注册表拒绝访问的方法

在某些情况下,为了配置系统更新相关服务(例如禁用 Windows 自动更新),我们需要更改注册表中 wuauserv 项的权限。本教程将带你一步步操作,成功获取并修改权限。 修改注册表路径: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\wuauserv 步骤一:打开注册表编辑…

深入解析 JDK jstack 命令:线程分析的利器

你点赞了吗&#xff1f;你关注了吗&#xff1f;每天分享干货好文。 高并发解决方案与架构设计。 海量数据存储和性能优化。 通用框架/组件设计与封装。 如何设计合适的技术架构&#xff1f; 如何成功转型架构设计与技术管理&#xff1f; 在竞争激烈的大环境下&#xff0c…

【操作系统原理03】处理机调度与死锁

文章目录 大纲一.处理机调度概念与层次0.大纲1.基本概念2.三个层次3.七状态模型4.三层调度都对比与联系 二.进程调度的时机&#xff0c;切换与过程的调度方式0.大纲1.进程调度时机2.调度方式3.进程的切换与过程 三.调度器和闲逛资源1.调度器/调度程序2.闲逛进程 四.调度算法的评…