Memento 备忘录模式

news2024/11/25 14:36:47

备忘录模式

  • 意图
  • 结构
  • 适用性
  • 实例
    • Java Web开发中的简单示例
      • Originator 类
      • Memento 类
      • Caretaker 类
    • 文本编辑器示例
      • 1. Originator (发起人) - `TextEditor`
      • 2. Memento (备忘录) - `TextMemento`
      • 3. Caretaker (负责人) - `History`
      • 4. 使用示例
      • 输出

备忘录模式(Memento Pattern)是一种行为设计模式,它允许在不违反封装原则的情况下捕获并恢复对象的内部状态。下面我将为你概述备忘录模式的意图、结构以及适用性,并提供一个简单的结构图描述。

意图

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

结构

备忘录模式主要包含以下角色:

  • Memento(备忘录) 存储原发器对象的内部状态,原发器根据需要决定备忘录存储原发器的哪些内部状态;防止原发器以外的其他对象访问备忘录。

  • Originator(原发器) 创建一个备忘录,用于记录当前时刻它的内部状态;使用备忘录恢复内部状态。

  • Caretaker(管理者) 负责保存好备忘录;不能对备忘录的内容进行操作或检查。

  • Caretaker 负责保存和恢复备忘录(Memento),但不负责查看或修改备忘录的内容。

  • Originator 创建一个备忘录,用来存储它的内部状态,并且可以在需要时从备忘录恢复其状态。

  • Memento 存储了Originator的状态。它通常提供给Originator一个宽接口来存取所有数据,而给Caretaker一个窄接口,只允许获取备忘录对象而不允许对其进行操作。

适用性

  • 当必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
  • 如果直接暴露对象的内部细节会导致对象的封装性被破坏,那么可以使用备忘录模式。
  • 当一个应用程序需要提供“撤销”操作时,可以通过保存历史状态来实现,这时可以考虑使用备忘录模式。

备忘录模式通过引入一个中介者(Caretaker)来维护备忘录对象,从而避免了直接访问原始对象的状态信息,保持了良好的封装性。这种模式在很多场景中都非常有用,比如文本编辑器中的撤消/重做功能,或者游戏中的存档/读档机制等。

实例

在Java Web开发中,备忘录模式可以用于多种场景,尤其是在需要保存和恢复用户会话状态、表单数据或业务对象的状态时。以下是一些可能的应用案例:

  1. 购物车功能:在电子商务网站中,用户的购物车内容是一个不断变化的状态集合。使用备忘录模式可以保存用户当前的购物车状态,以便在用户离开后返回时能够恢复到之前的状态。

  2. 在线编辑器:如果有一个基于Web的富文本编辑器或者代码编辑器,你可以使用备忘录模式来实现撤销(undo)和重做(redo)功能。每次用户进行更改时,都可以创建一个备忘录来存储当前文档的状态。

  3. 游戏状态保存:对于基于Web的游戏,可以使用备忘录模式来保存游戏进度。玩家可以在任何时候保存游戏状态,并且在以后继续游戏时加载该状态。

  4. 配置管理:在企业级应用中,系统管理员可能会对应用程序进行不同的配置设置。使用备忘录模式可以保存这些配置状态,使得管理员可以轻松地回滚到之前的配置。

  5. 工作流中的步骤保存:在多步骤的工作流或向导界面中,每个步骤都有自己的状态。备忘录模式可以帮助用户在流程中的任意一步之间来回切换,同时保持每一步的数据完整性和一致性。

Java Web开发中的简单示例

假设我们有一个简单的在线问卷应用,用户可以填写一系列问题。为了提供更好的用户体验,我们可以允许用户暂停并稍后从上次停止的地方继续。

Originator 类

public class Questionnaire {
    private String currentQuestion;
    private Map<String, String> answers;

    public Questionnaire() {
        this.answers = new HashMap<>();
    }

    // 设置当前问题
    public void setCurrentQuestion(String question) {
        this.currentQuestion = question;
    }

    // 获取当前问题
    public String getCurrentQuestion() {
        return currentQuestion;
    }

    // 添加答案
    public void addAnswer(String question, String answer) {
        this.answers.put(question, answer);
    }

    // 创建备忘录
    public QuestionnaireMemento createMemento() {
        return new QuestionnaireMemento(this.currentQuestion, new HashMap<>(this.answers));
    }

    // 从备忘录恢复
    public void setMemento(QuestionnaireMemento memento) {
        this.currentQuestion = memento.getCurrentQuestion();
        this.answers = new HashMap<>(memento.getAnswers());
    }
}

Memento 类

public class QuestionnaireMemento {
    private final String currentQuestion;
    private final Map<String, String> answers;

    public QuestionnaireMemento(String currentQuestion, Map<String, String> answers) {
        this.currentQuestion = currentQuestion;
        this.answers = answers;
    }

    public String getCurrentQuestion() {
        return currentQuestion;
    }

    public Map<String, String> getAnswers() {
        return answers;
    }
}

Caretaker 类

public class SessionCaretaker {
    private QuestionnaireMemento memento;

    public void save(Questionnaire questionnaire) {
        this.memento = questionnaire.createMemento();
    }

    public void restore(Questionnaire questionnaire) {
        if (this.memento != null) {
            questionnaire.setMemento(memento);
        }
    }
}

在这个例子中,Questionnaire是Originator,它负责创建和恢复备忘录;QuestionnaireMemento是Memento,它存储了Questionnaire的状态;SessionCaretaker是Caretaker,它保存了备忘录但不修改它。通过这种方式,即使用户离开了页面,也可以通过保存的备忘录恢复他们的进度。

当然,让我们用一个简单的例子来说明备忘录模式。假设我们有一个文本编辑器应用,用户可以在其中输入文本,并且能够撤销和重做他们的更改。我们将使用备忘录模式来实现这一功能。

文本编辑器示例

1. Originator (发起人) - TextEditor

TextEditor类代表文本编辑器,它拥有当前的文本状态,并能创建和恢复备忘录。

public class TextEditor {
    private String text;

    public TextEditor() {
        this.text = "";
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }

    // 创建备忘录
    public TextMemento createMemento() {
        return new TextMemento(this.text);
    }

    // 从备忘录恢复
    public void setMemento(TextMemento memento) {
        this.text = memento.getState();
    }
}

2. Memento (备忘录) - TextMemento

TextMemento类用来存储TextEditor的状态。在这个例子中,它只包含文本内容。

public class TextMemento {
    private final String state;

    public TextMemento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }
}

3. Caretaker (负责人) - History

History类负责保存和管理一系列的备忘录对象。这可以用来实现撤销和重做功能。

import java.util.Stack;

public class History {
    private Stack<TextMemento> mementos = new Stack<>();

    public void save(TextEditor editor) {
        mementos.push(editor.createMemento());
    }

    public void undo(TextEditor editor) {
        if (mementos.size() > 1) { // 确保至少有两个备忘录
            mementos.pop(); // 弹出最新的备忘录
            editor.setMemento(mementos.peek()); // 恢复到上一个状态
        } else if (mementos.size() == 1) {
            mementos.pop(); // 弹出唯一的备忘录
            editor.setText(""); // 清空文本
        }
    }
}

4. 使用示例

现在我们可以创建一个简单的控制台应用程序来展示如何使用这些类。

public class Main {
    public static void main(String[] args) {
        TextEditor editor = new TextEditor();
        History history = new History();

        editor.setText("Hello, world!");
        System.out.println("Initial text: " + editor.getText());

        // 保存当前状态
        history.save(editor);

        editor.setText("Goodbye, world!");
        System.out.println("Changed text: " + editor.getText());

        // 再次保存当前状态
        history.save(editor);

        // 撤销回到之前的状态
        history.undo(editor);
        System.out.println("After first undo: " + editor.getText());

        // 再次撤销回到最初的状态
        history.undo(editor);
        System.out.println("After second undo: " + editor.getText());
    }
}

输出

运行上述代码后,输出将是:

Initial text: Hello, world!
Changed text: Goodbye, world!
After undo: Hello, world!

这个例子展示了如何使用备忘录模式来实现简单的撤销功能。TextEditor是发起人,它能够创建和恢复自己的状态;TextMemento是备忘录,它存储了TextEditor的状态;而History是负责人,它保存了一系列的备忘录以便于撤销操作。通过这种方式,你可以轻松地扩展这个模型以支持更多的复杂功能,比如重做(redo)操作。

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

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

相关文章

网络应用技术 实验二:交换机VLAN 应用(华为ensp)

目录 一、实验简介 二、实验目的 三、实验需求 四、实验拓扑 五、实验任务及要求 1、任务 1&#xff1a;在交换机上创建VLAN 并测试通信 2、任务 2&#xff1a;路由交换机实现VLAN 之间通信 六、实验步骤 1、完成任务 1 2、完成任务 2 一、实验简介 在交换机上配置 VLAN&#x…

大模型应用:新时代的多模态交互

引言 如果把大模型接入到终端设备&#xff0c;会怎么样&#xff1f; &#xff08;1&#xff09;智能交互回顾 历史文章《[智能交互复兴&#xff1a;ChatGPT 终端&#xff08;奔驰/Siri&#xff09; &#xff1f;]》中提到&#xff1a;大模型遍布多个应用场景 其中有智能对话…

一周内从0到1开发一款 AR眼镜 相机应用?

目录 1. &#x1f4c2; 前言 2. &#x1f4a0; 任务拆分 2.1 产品需求拆分 2.2 开发工作拆分 3. &#x1f531; 开发实现 3.1 代码目录截图 3.2 app 模块 3.3 middleware 模块 3.4 portal 模块 4. ⚛️ 拍照与录像 4.1 前滑后滑统一处理 4.2 初始化 View 以及 Came…

信息安全工程师(76)网络安全应急响应技术原理与应用

前言 网络安全应急响应&#xff08;Network Security Incident Response&#xff09;是针对潜在或已发生的网络安全事件而采取的网络安全措施&#xff0c;旨在降低网络安全事件所造成的损失并迅速恢复受影响的系统和服务。 一、网络安全应急响应概述 定义&#xff1a;网络安全应…

用图说明 CPU、MCU、MPU、SoC 的区别

CPU CPU 负责执行构成计算机程序的指令&#xff0c;执行这些指令所指定的算术、逻辑、控制和输入/输出&#xff08;I/O&#xff09;操作。 MCU (microcontroller unit) 不同的 MCU 架构如下&#xff0c;注意这里的 MPU 表示 memory protection unit MPU (microprocessor un…

vue3动态监听div高度案例

案例场景 场景描述&#xff1a;现在左边的线条长度需要根据右边盒子的高度进行动态变化 实践代码案例 HTML部分 <div v-for"(device, index) in devices" :key"index"><!-- 动态设置 .left-bar 的高度 --><div class"left-bar"…

【Docker系列】指定系统平台拉取 openjdk:8 镜像

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【含文档+源码】基于SpringBoot+Vue的新型吃住玩一体化旅游管理系统的设计与实现

开题报告 本文旨在探讨新型吃住玩一体化旅游管理系统的设计与实现。该系统融合了用户注册与登录、旅游景点管理、旅游攻略发帖、特色旅游路线推荐、附近美食推荐以及酒店客房推荐与预定等多项功能&#xff0c;旨在为游客提供全方位、一体化的旅游服务体验。在系统设计中&#…

B3735 [信息与未来 2018] 圣诞树

题目描述 圣诞树共有 nn 层&#xff0c;从上向下数第 11 层有 11 个星星、第 22 层有 22 个星星、以此类推&#xff0c;排列成下图所示的形状。 星星和星星之间用绳子连接。第 1,2,\cdots, n - 11,2,⋯,n−1 层的每个星星都向下一层最近的两个星星连一段绳子&#xff0c;最后一…

解决 Hypack 安装不能正常运行的引导及微软 VC++ 运行库 VCRedist

解决 Hypack 安装不能正常运行的引导及微软 VC 运行库 VCRedist 前言1、常见 Hypack 安装不能正常运行的错误1.1、无法打开大地测量参数1.2、无法运行硬件设置和组合 2、从 Hypack 2013 开始&#xff0c;程序安装后&#xff0c;在程序目标目录&#xff0c;有支持目录 Support &…

给大模型研究生一些救命建议

这篇写给大模型方向的研一新生&#xff0c;我呆证看完以后能救你们大命 首先我知道大模型算法工程师这个 title 十分诱人&#xff0c;你们现在也被导师说得一腔热血。 但是&#xff0c;大模型它跟七八年前的 CV、NLP 都不太一样&#xff0c;最不一样的点在哪里呢? 就是LLM …

Oracle基础查询

第一章 数据查询 1.1 单表查询 1.1.1 数据准备 找到分享的sql文件&#xff0c;选中文件&#xff0c;右键进行复制&#xff0c;选中以wateruser用户登录的连接&#xff0c;右键粘贴&#xff0c;然后ok确认&#xff0c;就可以将两个sql文件添加到了Datagrip的工程中&#xff0c;打…

解决com.mysql.jdbc.NonRegisteringDriver内存泄漏问题

1. 问题背景 线上出现内存报警&#xff0c;通过dump文件&#xff0c;MAT分析&#xff0c;发现mysql-connector-java 有内存泄漏问题 2.问题分析 然后看大对象列表&#xff0c;NonRegisteringDriver 对象确实占内存比较多&#xff0c;里面村的数据库连接的虚引用占比较多 3.解…

如何优雅处理异常?处理异常的原则

前言 在我们日常工作中&#xff0c;经常会遇到一些异常&#xff0c;比如&#xff1a;NullPointerException、NumberFormatException、ClassCastException等等。 那么问题来了&#xff0c;我们该如何处理异常&#xff0c;让代码变得更优雅呢&#xff1f; 1 不要忽略异常 不知…

华为2288HV2服务器安装BCLinux8U6无法显示完整安装界面的问题处理

本文记录了华为2288HV2服务器安装BCLinux8U6无法显示完整安装界面&#xff0c;在安装过程中配置选择时&#xff0c;右侧安装按钮不可见&#xff0c;导致安装无法继续的问题处理过程。 一、问题现象 华为2288HV2服务器安装BCLinux8U6时无法显示完整的安装界面&#xff0c;问题…

Qt多边形填充/不填充绘制

1 填充多边形绘制形式 void GraphicsPolygonItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {Q_UNUSED(option);Q_UNUSED(widget);//painter->setPen(pen()); // 设置默认画笔//painter->setBrush(brush()); // 设置默…

Python设计模式探究:单例模式实现及应用解析

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storm…

Linux权限解析:用户、组和权限的协同

​​​​​​​在Linux系统中&#xff0c;权限决定了谁能做什么。本文将指导你如何掌握这些权限&#xff0c;以确保你的系统既安全又高效&#xff01; 目录 1.shell命令及其运行原理 2.Linu权限的概念 (1) 用户 (2) 切换用户命令su (3) 指令提权命令sudo (4) 什么是权限…

java、excel表格合并、指定单元格查找、合并文件夹

#创作灵感# 公司需求 记录工作内容 后端&#xff1a;JAVA、Solon、easyExcel、FastJson2 前端&#xff1a;vue2.js、js、HTML 模式1&#xff1a;合并文件夹 * 现有很多文件夹 想合并全部全部的文件夹的文件到一个文件夹内 * 每个部门发布的表格 合并全部的表格为方便操作 模…

koa项目实战 == 实现注册登录鉴权

一. 项目的初始化 1 npm 初始化 npm init -y生成package.json文件: 记录项目的依赖 2 git 初始化 git init生成’.git’隐藏文件夹, git 的本地仓库 3 创建 ReadMe 文件 二. 搭建项目 1 安装 Koa 框架 npm install koa2 编写最基本的 app 创建src/main.js const Koa…