Memento 备忘录模式

备忘录模式

  • 意图
  • 结构
  • 适用性
  • 实例
    • 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)操作。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HTMLCSS:3D 旋转卡片的炫酷动画

效果演示 这段代码是一个HTML和CSS的组合&#xff0c;用于创建一个具有3D效果的动画卡片。 HTML <div class"obj"><div class"objchild"><span class"inn6"><h3 class"text">我是谁&#xff1f;我在那<…

为什么越来越多人开始用云电脑?网友道出了真相

近期&#xff0c;3A游戏大作《黑神话&#xff1a;悟空》的横空出世&#xff0c;成功激起大多数人对国产游戏的兴趣。然而&#xff0c;没有一台高配置的电脑&#xff0c;就无法在《黑神话&#xff1a;悟空》中获得震撼的游戏体验。想要配齐处理器、显卡、内存等硬件&#xff0c;…

https服务器访问http资源报Mixed Content混合内容错误

1 报错内容 Mixed Content: The page at ‘https://xxx’ was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint ‘http://xxx’. This request has been blocked; the content must be served over HTTPS. 2 报错原因 页面通过 HTTPS 加载&#xff…

vue3项目中实现el-table分批渲染表格

开篇 因最近工作中遇到了无分页情景下页面因大数据量卡顿的问题&#xff0c;在分别考虑并尝试了懒加载、虚拟滚动、分批渲染等各个方法后&#xff0c;最后决定使用分批渲染来解决该问题。 代码实现 表格代码 <el-table :data"currTableData"borderstyle"wi…

多模态PaliGemma——Google推出的基于SigLIP和Gemma的视觉语言模型

前言 本文怎么来的呢&#xff1f;其实很简单&#xff0c;源于上一篇文章《π0——用于通用机器人控制的流匹配VLA模型&#xff1a;一套框架控制7种机械臂(改造了PaliGemma和ACT的3B模型)》中的π0用到了PaliGemma 故本文便来解读下这个PaliGemma 第一部分 PaliGemma 1.1 Pal…

基于vue框架的的楼盘销售管理系统6n60a(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 用户,房源类型,员工,房源信息,购房预订,购房合同 开题报告内容 基于Vue框架的楼盘销售管理系统开题报告 一、研究背景 随着房地产市场的蓬勃发展&#xff0c;楼盘销售行业的竞争日益激烈。传统的销售管理方式依赖于人工记录和纸质文档&#xff0c;效率低下…

DevOps开发运维简述

DevOps平台是一套集成的解决方案&#xff0c;旨在协调软件开发&#xff08;Development&#xff09;和信息技术运维&#xff08;Operations&#xff09;。它促进跨功能团队合作&#xff0c;实现自动化流程&#xff0c;确保持续集成与持续交付&#xff08;CI/CD&#xff09;。 一…

如何记住美好的时刻,使用标准 SAP NetWeaver 日志的可能性

在本文中&#xff0c;我们将介绍一些常见的技巧&#xff0c;以及是否有针对它们的标准文档&#xff08;请参阅 Auding and Logging 寻求帮助&#xff09;。在本文中&#xff0c;我们将主要考虑标准工具。所有代码清单都可以在 ZABAPFILEOS_07 年的 github 上找到。 SAP NetWea…

ONLYOFFICE 8.2深度体验:高效协作与卓越性能的完美融合

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ONLYOFFICE 8.2 &#x1f50d;引言&#x1f4d2;1. ONLYOFFICE 产品简介&#x1f4da;2. 功能与特点&#x1f341;协作编辑 PDF&#x1f342;…

[mysql]修改表和课后练习

目录 DDL数据定义语言 添加一个字段 添加一个字段到最后一个 添加到表中的第一个一个字段 选择其中一个位置: 修改一个字段:数据类型,长度,默认值(略) 重命名一个字段 删除一个字段 重命名表 删除表 清空表 DCL中事务相关内容 DCL中COMMIT和ROLLBACK的讲解 对比TR…

MinerU容器构建教程

一、介绍 MinerU作为一款智能数据提取工具&#xff0c;其核心功能之一是处理PDF文档和网页内容&#xff0c;将其中的文本、图像、表格、公式等信息提取出来&#xff0c;并转换为易于阅读和编辑的格式&#xff08;如Markdown&#xff09;。在这个过程中&#xff0c;MinerU需要利…

使用 OpenCV 实现图像的透视变换

概述 在计算机视觉领域&#xff0c;经常需要对图像进行各种几何变换&#xff0c;如旋转、缩放和平移等。其中&#xff0c;透视变换&#xff08;Perspective Transformation&#xff09;是一种非常重要的变换方式&#xff0c;它能够模拟三维空间中的视角变化&#xff0c;例如从…

三十二、Python基础语法(面向对象其他语法-上)

一、权限 权限&#xff1a;在 Python 中&#xff0c;可以对方法和属性设置访问权限,&#xff0c;即规定在什么地方可以使用这些属性和方法。 1.公有 公有&#xff1a;可以在任意的地方通过对象调用&#xff0c;按照之前的方式&#xff0c;直接定义的属性和方法都是公有的。 …

Jmeter命令监控CPU等指标

JMeter 命令行执行脚本得到的报告中&#xff0c;是没有CPU、内存使用率等监控数据的&#xff0c;但是可以使用JMeter插件帮忙。 一、下载jmeter-plugins-manager.jar 下载后将文件放到jmeter安装包lib/ext目录下。打开Jmeter》菜单栏》选项》Plugins Manager 二、安装PerfMon…

【IF-MMIN】利用模态不变性特征进行缺失模态的鲁棒多模态情感识别

代码地址&#xff1a;github地址传送 文章是基于MMIN的改进 -> MMIN传送 abstract 多模态情感识别利用跨模态的互补信息来获得性能。然而&#xff0c;我们不能保证所有模式的数据总是存在于实践中。在跨模态数据缺失预测研究中&#xff0c;异质性模态之间的固有差异即模态…

vueui vxe-form 分享实现表单项的联动禁用,配置式表单方式的用法

官网文档&#xff1a;https:/vxeui.com 实现表单项的联动禁用 在使用 vxe-form 时&#xff0c;有时候需要将表单项直接进行关联操作&#xff0c;比如某一项选择后&#xff0c;另外一项设置为禁用状态不可选择&#xff0c;使用插槽的话神容易实现&#xff0c;本章是分享配置式的…

架构师备考-系统分析与设计(面向对象方法)

定义 面向对象开发方法将面向对象的思想应用于软件开发过程中&#xff0c;指导开发活动&#xff0c;是建立在“对象”概念基础上的方法学。面向对象方法的本质是主张参照人们认知一个显示系统的方法&#xff0c;完成分析、设计与实现一个软件系统&#xff0c;提倡用人类…

【Melty是一款开源的AI编程助手,基于codellama,媲美cusor】

https://github.com/meltylabs/melty.git 对话进行代码重构

java项目之校园周边美食探索及分享平台(springboot)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的校园周边美食探索及分享平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 校园周边美食…

在Vue和OpenLayers中使用移动传感器实现飞机航线飞行模拟

项目实现的核心代码 项目概述 该项目的目标是使用Vue.js作为前端框架&#xff0c;结合OpenLayers用于地图显示&#xff0c;实时获取来自手机传感器的数据&#xff08;如经纬度、高度、速度&#xff09;来模拟飞机在地图上的飞行轨迹。整体架构如下&#xff1a; Vue.js 用于构建…