备忘录模式的理解和实践

引言

        在软件开发中,我们经常会遇到需要保存对象状态并在某个时间点恢复到该状态的需求。这种需求类似于我们平时说的“后悔药”,即允许用户撤销之前的操作,恢复到某个之前的状态。备忘录模式(Memento Pattern)正是为了解决这类问题而诞生的设计模式之一。本文将详细讲解备忘录模式的概念、原理及其在Java中的实践应用。

一、备忘录模式概述

1.1 定义

        备忘录模式是一种行为设计模式,用于在不暴露对象实现细节的情况下,捕获并保存对象的内部状态,以便以后可以将对象恢复到这个状态。该模式的主要目的是允许用户恢复到对象之前的状态,从而提供某种形式的撤销功能。

1.2 结构

        备忘录模式包含三个主要角色:

  • 发起人(Originator):创建并恢复备忘录的对象。
  • 备忘录(Memento):存储发起人内部状态的快照,并且防止其他对象访问备忘录。备忘录通常只有发起人可以访问其内容。
  • 管理者(Caretaker):负责保存和恢复备忘录,但不能检查或操作备忘录的内容。

1.3 原理

  1. 创建备忘录:发起人通过调用自身的方法创建当前状态的备忘录。
  2. 保存备忘录:管理者接收并保存发起人创建的备忘录。
  3. 恢复状态:发起人通过管理者获取之前保存的备忘录,并恢复到该状态。

二、备忘录模式的优点和缺点

2.1 优点

  • 提供了撤销功能:用户可以通过恢复备忘录来撤销之前的操作。
  • 封装性强:备忘录对象只由发起人创建和解释,外部对象无法直接访问其内容,增强了封装性。
  • 易于实现:备忘录模式相对简单,易于理解和实现。

2.2 缺点

  • 资源开销:保存多个备忘录对象会占用较多的内存资源。
  • 实现复杂:在复杂系统中,创建和恢复备忘录可能需要较多的代码,增加了系统的复杂性。

三、备忘录模式的实践

        下面我们以一个简单的文本编辑器为例,演示如何使用备忘录模式实现撤销功能。

3.1 发起人(Originator)

// 发起人接口
public interface Originator {
    void setState(String state);
    String getState();
    Memento createMemento();
    void setMemento(Memento memento);
}

// 具体的发起人类
public class TextEditor implements Originator {
    private String content;

    @Override
    public void setState(String state) {
        this.content = state;
    }

    @Override
    public String getState() {
        return this.content;
    }

    @Override
    public Memento createMemento() {
        return new TextMemento(content);
    }

    @Override
    public void setMemento(Memento memento) {
        if (memento instanceof TextMemento) {
            this.content = ((TextMemento) memento).getContent();
        }
    }
}


3.2 备忘录(Memento)

// 备忘录接口
public interface Memento {
}

// 具体的备忘录类
public class TextMemento implements Memento {
    private String content;

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

    public String getContent() {
        return content;
    }
}


3.3 管理者(Caretaker)

import java.util.ArrayList;
import java.util.List;

// 管理者类
public class Caretaker {
    private List<Memento> mementoList = new ArrayList<>();

    public void add(Memento memento) {
        mementoList.add(memento);
    }

    public Memento get(int index) {
        return mementoList.get(index);
    }
}


3.4 客户端代码

public class Client {
    public static void main(String[] args) {
        TextEditor editor = new TextEditor();
        Caretaker caretaker = new Caretaker();

        editor.setState("First state");
        caretaker.add(editor.createMemento());

        editor.setState("Second state");
        caretaker.add(editor.createMemento());

        editor.setState("Third state");

        // 回滚到第二个状态
        System.out.println("Current State: " + editor.getState());
        editor.setMemento(caretaker.get(1));
        System.out.println("Rollback to State: " + editor.getState());

        // 回滚到第一个状态
        editor.setMemento(caretaker.get(0));
        System.out.println("Rollback to State: " + editor.getState());
    }
}


3.5 运行结果

Current State: Third state
Rollback to State: Second state
Rollback to State: First state


四、备忘录模式的应用场景

备忘录模式在实际开发中有很多应用场景,以下是一些常见的例子:

  • 文本编辑器:撤销和重做功能。
  • 数据库事务:保存事务开始前的状态,以便在事务失败时回滚。
  • 游戏开发:保存游戏进度,允许玩家在失败时重新开始。
  • 绘图软件:撤销和重做绘图操作。

总结

        备忘录模式是一种强大的设计模式,用于在不暴露对象内部实现细节的情况下保存和恢复对象的状态。通过引入备忘录对象,我们可以在需要时恢复到对象之前的状态,从而实现撤销功能。虽然备忘录模式在资源开销和实现复杂度上有一些缺点,但在许多应用场景中,它仍然是一种非常有效的解决方案。

        希望本文能帮助你理解备忘录模式,并通过具体的Java代码示例掌握其实现方法。如果你在实际开发中遇到需要撤销功能的需求,不妨尝试一下备忘录模式,相信它会给你的项目带来很大的帮助。

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

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

相关文章

云端微光,AI启航:低代码开发的智造未来

文章目录 前言一、引言&#xff1a;技术浪潮中的个人视角初次体验腾讯云开发 Copilot1.1 低代码的时代机遇1.1.1 为什么低代码如此重要&#xff1f; 1.2 AI 的引入&#xff1a;革新的力量1.1.2 Copilot 的亮点 1.3 初学者的视角1.3.1 Copilot 带来的改变 二、体验记录&#xff…

(css)element中el-select下拉框整体样式修改

(css)element中el-select下拉框整体样式修改 重点代码&#xff08;颜色可行修改&#xff09; // 修改input默认值颜色 兼容其它主流浏览器 /deep/ input::-webkit-input-placeholder {color: rgba(255, 255, 255, 0.50); } /deep/ input::-moz-input-placeholder {color: rgba…

Ungoogled Chromium127编译指南 Windows篇 - 获取源码(七)

1. 引言 在完成所有必要工具的安装和配置后&#xff0c;我们进入了Ungoogled Chromium编译过程的第一个关键阶段&#xff1a;获取源代码。本文将详细介绍如何正确获取和准备Ungoogled Chromium的源代码&#xff0c;为后续的编译工作打下基础。 2. 准备工作 2.1 环境检查 在…

802数据结构:2022年真题选择题

目录 前言 一、 选择题&#xff08;本大题共 15小题&#xff0c;每小题 2分&#xff0c;共 30分&#xff09; 1、当输入非法错误时一个“好”的算法会进行适当处理而不会产生难以理解的输出结果。这称为算法的&#xff08;&#xff09;。A可读性    B.健壮性    C.正确性…

汽车零部件设计之——发动机曲轴预应力模态分析仿真APP

汽车零部件是汽车工业的基石&#xff0c;是构成车辆的基础元素。一辆汽车通常由上万件零部件组成&#xff0c;包括发动机系统、传动系统、制动系统、电子控制系统等&#xff0c;它们共同确保了汽车的安全、可靠性及高效运行。在汽车产业快速发展的今天&#xff0c;汽车零部件需…

QT实战--带行号的支持高亮的编辑器实现(2)

本文主要介绍了第二种实现带行号的支持高亮的编辑器的方式,基于QTextEdit实现的,支持自定义边框,背景,颜色,以及滚动条样式,支持输入变色,复制文本到里面变色,支持替换,是一个纯专业项目使用的编辑器 先上效果图: 1.头文件ContentTextEdit.h #ifndef CONTENT_TEXT_…

【JAVA】旅游行业中大数据的使用

一、应用场景 数据采集与整合&#xff1a;全面收集旅游数据&#xff0c;如客流量、游客满意度等&#xff0c;整合形成统一数据集&#xff0c;为后续分析提供便利。 舆情监测与分析&#xff1a;实时监测旅游目的地的舆情信息&#xff0c;运用NLP算法进行智能处理&#xff0c;及…

vxe-grid使用问题

目录 1.slot中使用模板字符串 2.合并表头 坑1&#xff1a;合并表头后一窜一窜的位置 坑2&#xff1a;合并表头后页面位置不够大&#xff0c;表头合并的位置就又窜了 3.footer-method部分行高 4.整列居左的前提下设置前几行居中 坑1&#xff1a;样式加不上去 坑2&#x…

Unity3D下采集camera场景并推送RTMP服务实现毫秒级延迟直播

技术背景 好多开发者&#xff0c;希望我们能够分享下如何实现Unity下的camera场景采集并推送rtmp服务&#xff0c;然后低延迟播放出来。简单来说&#xff0c;在Unity 中实现采集 Camera 场景并推送RTMP的话&#xff0c;先是获取 Camera 场景数据&#xff0c;通过创建 RenderTex…

分布式 Raft算法 总结

前言 相关系列 《分布式 & 目录》《分布式 & Raft算法 & 总结》《分布式 & Raft算法 & 问题》 参考文献 《Raft一致性算法论文译文》《深入剖析共识性算法 Raft》 简介 Raft 木筏是一种基于日志复制实现的分布式容错&一致性算法。在Raft算法…

System.Data.OracleClient 需要 Oracle 客户端软件 version 8.1.7 或更高版本

问题1&#xff1a;“/”应用程序中的服务器错误。 System.Data.OracleClient 需要 Oracle 客户端软件 version 8.1.7 或更高版本。 说明: 执行当前 Web 请求期间&#xff0c;出现未经处理的异常。请检查堆栈跟踪信息&#xff0c;以了解有关该错误以及代码中导致错误的出处的详细…

JAVA |日常开发中Websocket详解

JAVA &#xff5c;日常开发中Websocket详解 前言一、Websocket 概述1.1 定义1.2 优势 二、Websocket 协议基础2.1 握手过程2.2 消息格式2.3 数据传输方式 三、Java 中使用 Websocket3.1 Java WebSocket API&#xff08;JSR - 356&#xff09;3.2 第三方库&#xff08;如 Tyrus&…

SpringBoot Maven快速上手

文章目录 一、Maven 1.1 Maven 简介&#xff1a;1.2 Maven 的核心功能&#xff1a; 1.2.1 项目构建&#xff1a;1.2.2 依赖管理&#xff1a; 1.3 Maven 仓库&#xff1a; 1.3.1 本地仓库&#xff1a;1.3.2 中央仓库&#xff1a;1.3.3 私服&#xff1a; 二、第一个 SpringBoot…

【论文阅读】处理器芯片敏捷设计方法:问题与挑战

作者&#xff1a;包云岗老师 包云岗老师是计算机体系结构方向的大牛&#xff0c;推动了体系结构方面的开源事业! 欢迎对本栏目感兴趣的人学习"一生一芯"~ 学习体会&#xff1a; 已有的软硬件生态系统和开发成本制约了对新结构的探索。但目前仍在几种路线上做尝试~ 1…

方案介绍|CW32L010安全低功耗MCU:驱动高速风筒新力量

吹风机一直以来都是消费者日常生活中的高频刚需产品&#xff0c;而高速风筒更是因为其快速干发、护发养发和低噪音的优势&#xff0c;逐渐成为家庭不可或缺的电器之一。 高速风筒通过采用高速电机和优化的气流设计&#xff0c;能够在短时间内快速吹干头发&#xff0c;同时减少…

uniapp uni-table最简单固定表头

需求&#xff1a;固定表头数据&#xff0c;在网上找了半天&#xff0c;啥都有&#xff0c;就是一直实现不了&#xff0c;最后更改代码实现 1.效果 2.主要代码讲解完整代码 表格的父级一定要设置高度&#xff0c;不然会错位&#xff0c;我看网上说设置position&#xff1a;fixed…

单元测试SpringBoot

添加测试专用属性 加载测试专用bean Web环境模拟测试 数据层测试回滚 测试用例数据设定

9. Win11上原生运行Ubuntu

本文介绍如何在win11原生系统上运行ubuntu&#xff0c;不需要额外安装虚拟机&#xff0c;以及如何配置网络等。 1.安装正版Win11 由于正版Win11需要钱&#xff0c;网上能破解的win11可能有问题&#xff0c;但是它们的破解工具&#xff0c;却是能正常用的&#xff0c;所以&…

小皮面板(PHPSTUDY)配置多个域名或IP

问题描述 小皮面板默认采用nginx的静态部署&#xff0c;按照使用nginx的习惯只需要额外添加一个server即可&#xff0c;但是会发现直接往配置文件里添加新的server是不生效的&#xff0c;小皮的官网论坛几乎已经停止维护&#xff0c;因此资料较少&#xff0c;原本也没有仔细使…

基于自注意力网络的SASRec

运用了自注意力网络&#xff08;self-attention network&#xff0c;SAN&#xff09;的序列推荐算法&#xff08;SASRec&#xff09;能以并行化的方式捕捉同一序列上不同时间步间的转移关系&#xff0c;最后通过加权求和的方式得出每个时间步的序列特征。 算法原理&#xff1a;…