Java设计模式之行为型模式(备忘录模式)实现方式详解

最近看到一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站

一、基础实现结构

  1. 角色定义与代码骨架
    备忘录模式包含三个核心角色,其协作关系如下:
  • Originator(发起人):需保存/恢复状态的对象,负责创建和使用备忘录。
  • Memento(备忘录):存储发起人状态的载体,通常设计为不可变类。
  • Caretaker(管理者):管理备忘录对象,不操作其内容。
    代码示例(文本编辑器场景):
// 发起人:文本编辑器
public class Editor {private String content;// 创建备忘录public Memento save() {return new Memento(this.content);}// 从备忘录恢复状态public void restore(Memento memento) {this.content = memento.getState();}
}
// 备忘录:存储状态
public class Memento {private final String state;  // 不可变状态public Memento(String state) { this.state = state; }public String getState() { return state; }
}
// 管理者:保存备忘录列表
public class History {private List mementos = new ArrayList<>();public void add(Memento memento) { mementos.add(memento); }public Memento get(int index) { return mementos.get(index); }
}
  1. 状态保存与恢复流程
// 客户端调用示例
Editor editor = new Editor();
History history = new History();
editor.setContent("Initial text");
history.add(editor.save());  // 保存状态1
editor.setContent("Modified text");
history.add(editor.save());  // 保存状态2
// 恢复到状态1
editor.restore(history.get(0));
System.out.println(editor.getContent());  // 输出:Initial text

二、高级实现技巧

  1. 封装性优化
  • 黑箱实现:将Memento作为Originator的内部类,限制外部访问。
    public class Editor {private String content;// 内部类备忘录public class EditorMemento {private final String state;private EditorMemento() { this.state = content; }  // 仅内部可访问}public EditorMemento save() { return new EditorMemento(); }
    }
    
  • 窄接口与宽接口:通过包级私有访问控制,仅允许Originator读取Memento内部状态。
  1. 多状态管理
    使用栈结构实现撤销/重做功能:
public class History {private Stack undoStack = new Stack<>();private Stack redoStack = new Stack<>();public void push(Memento memento) { undoStack.push(memento); }public Memento undo() { return undoStack.pop(); }public void redo(Memento memento) { redoStack.push(memento); }
}
  1. 资源优化
  • 增量存储:仅保存状态差异而非全量数据。
  • 序列化:通过Serializable接口持久化备忘录至文件或数据库。
    // 发起人支持序列化
    public class SerializableOriginator extends Originator implements Serializable {private String state;// 实现序列化逻辑
    }
    

三、实际应用示例

  1. 游戏存档系统
// 发起人:游戏角色
public class Gamer {private int level;private Inventory items;public GamerMemento save() {return new GamerMemento(level, items.clone());}public void restore(GamerMemento memento) {this.level = memento.getLevel();this.items = memento.getItems();}// 备忘录类(内部类)public static class GamerMemento {private final int level;private final Inventory items;// 构造函数与Getter}
}
  1. 数据库事务回滚
public class DatabaseTransaction {private TableData originalData;public TransactionMemento snapshot() {return new TransactionMemento(originalData.clone());}public void rollback(TransactionMemento memento) {this.originalData = memento.getData();}
}

四、测试与调试

  1. 单元测试要点
  • 状态一致性验证:使用断言检查恢复后的状态是否与预期一致。
    assertEquals("Initial text", editor.getContent());
    
  • 异常场景测试:模拟空备忘录或非法恢复操作。
    assertThrows(IllegalStateException.class, () -> editor.restore(null));
    
  1. 性能监控
  • 内存占用分析:通过Profiler工具监控备忘录对象的数量与大小。
  • 优化策略:限制备忘录历史数量(如仅保存最近10个状态)。

五、常见问题与解决方案

问题解决方案
内存溢出使用LRU算法淘汰旧备忘录,或采用增量存储。
状态不一致确保Memento不可变,避免外部修改。
跨会话恢复失败将备忘录序列化至持久化存储(如文件或数据库)。

六、总结

备忘录模式通过状态快照与封装隔离机制,为撤销、回滚等场景提供了灵活的解决方案。实现时需注重:

  1. 职责分离:明确OriginatorMementoCaretaker的边界。
  2. 资源管理:根据场景选择内存存储或持久化方案。
  3. 封装性保护:通过内部类或访问控制限制备忘录访问。
    该模式广泛应用于编辑器、游戏、数据库等领域,是实现无副作用状态管理的核心工具。

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

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

相关文章

k8s:离线部署tomcatV11.0.9,报Cannot find /opt/bitnami/tomcat/bin/setclasspath.sh

本文记录了在离线环境下部署Tomcat容器时遇到的权限问题及解决方案。在Docker环境中运行Tomcat时出现&quot;找不到setclasspath.sh&quot;错误&#xff0c;通过添加--security-opt seccompunconfined参数解决。在Kubernetes环境中部署时出现相同问题&#xff0c;通过设置…

Linux操作系统之线程(五):线程封装

目录 前言 一、线程ID及进程地址空间布局 二、线程栈与线程局部存储 三、线程封装 总结&#xff1a; 前言 我们在上篇文章着重给大家说了一下线程的控制的有关知识。 但是如果我们要使用线程&#xff0c;就得那这pthread_create接口直接用吗&#xff1f;这样岂不是太过麻…

【物理与机器学习】从非平衡热力学到扩散模型

[toc] 0.引子:从非平衡热力学开始 1.架构简介 2.反向过程的具体推导与 DDPM 改进摘要&#xff1a;扩散模型将非平衡热力学的“噪声注入—去噪逆转”理念注入生成建模中。DDPM&#xff08;Denoising Diffusion Probabilistic Models&#xff09;在 SD2015 的基础上&#xff0c;通…

Git常用命令详解:从入门到精通

前言 Git作为当今最流行的分布式版本控制系统&#xff0c;已经成为开发者必备的技能之一。无论你是独立开发者还是团队协作&#xff0c;掌握Git的基本操作都能极大提高工作效率。本文将详细介绍Git的常用命令&#xff0c;帮助你快速上手并精通Git的基本使用。 一、Git基础概念…

Vue-22-通过flask接口提供的数据使用plotly.js绘图(一)

文章目录 1 任务背景 2 Flask提供接口(server.py) 2.1 原始代码 2.2 跨域问题 3 Vue3获取数据并渲染Plotly图表 3.1 新建工程 3.2 程序 3.2.1 index.html(入口) 3.2.2 cpmponents/Plot.vue(子组件) 3.2.3 App.vue(父组件) 3.2.4 main.ts 3.3 展示 4 选择图表类型绘图 4.1 App.v…

【mysql】换主键

需求&#xff1a;曲库表的主键错了&#xff0c;原先设置的是(sang_id),应该设置为&#xff08;sang_name,singer&#xff09;联合主键。-- &#xff08;0&#xff09;先备份数据&#xff0c;我这里没备份 -- &#xff08;1&#xff09;进行主键的切换之前&#xff0c;要进行一些…

Redis原理之缓存

上篇文章&#xff1a; Redis原理之集群https://blog.csdn.net/sniper_fandc/article/details/149141342?fromshareblogdetail&sharetypeblogdetail&sharerId149141342&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 目录 1 Redis作为MySQL…

关于集合的底层数据结构

单列集合Collection分为list集合和set集合list集合分为ArrayList和LinkedListArrayList--底层数据结构是数组1.通过索引查询快2.增删要重构索引,增删慢 LinkedList--底层数据结构是链表1.无索引查询慢2.通过改变前节点的尾指针和后节点的前指针指向可快速增删,增删快set集合(…

批量插入技巧:减少事务提交次数的性能提升

一、事务提交成本分析每次事务提交触发‌磁盘I/O同步‌&#xff08;WAL机制&#xff09;、‌日志写入‌和‌锁资源释放‌操作&#xff0c;高频独立提交会产生指数级开销‌。实验表明&#xff1a;MySQL提交1万次单条插入比单次批量插入‌慢20倍以上‌‌。高频提交还加剧锁竞争与…

importlib.import_module() 的用法与实战案例

&#x1f31f; 一、什么是 importlib&#xff1f; importlib 是 Python 的一个内置标准库&#xff0c;用于在程序运行时 动态导入模块。 &#x1f524; 对比&#xff1a;普通 import vs importlib方式示例特点静态导入import os编写代码时就确定要导入的模块动态导入importlib.…

Oracle 12c 创建数据库初级教程

1. 连接到Oracle sqlplus / as sysdba Oracle数据库名称默认为ORCL或sqlplus /ORCL as sysdba Oracle数据库名称默认为ORCL2. 创建表空间&#xff08;数据库&#xff09; create user YOUR_USERNAME identified by "YOUR_PASSWORD"; YOUR_USERNAME为数据库名称和登…

zabbix服务器告警处理

zabbix服务器告警&#xff0c;信息为&#xff1a;Utilization of poller processes over 75%处理办法为修改zabbix_server.conf配置文件&#xff0c;一般情况下为/etc/zabbix目录下。根据自己轮询器的类型修改对应的轮询器的数量&#xff1b;我这里把StartPollers&#xff0c;S…

随笔20250721 PostgreSQL实体类生成器

我来帮你创建一个C#程序&#xff0c;从PostgreSQL数据库读取表结构并生成对应的实体类文件。我已经创建了一个完整的PostgreSQL实体类生成器。这个程序包含以下主要功能&#xff1a;主要特性数据库连接: 使用Npgsql连接PostgreSQL数据库表结构读取: 自动读取所有表的结构信息类…

B树、B-树与B+树

B树、B-tree与B树 在计算机科学&#xff0c;尤其是数据库和文件系统的领域中&#xff0c;B树、B-tree和B树是理解数据如何被高效存储和检索的关键。它们之间关系紧密&#xff0c;但功能和应用上又存在着决定性的差异。 一、 核心概念澄清&#xff1a;B树就是B-tree 首先需要明确…

视频格式转换工厂v3.2.5,集音视频、图片处理78MB

今天&#xff0c;我们要介绍的是一款功能强大的视频处理软件——视频格式转换工厂。这款软件已经完美破解&#xff0c;无需登录即可享受全部高级功能。它不仅支持视频格式转换&#xff0c;还涵盖了音频、图片处理等多种功能&#xff0c;是一款真正的多媒体处理工具。 视频格式转…

VUE 中父级组件使用JSON.stringify 序列化子组件传递循环引用错误

背景 VUE 中父级组件使用JSON.stringify 序列化子组件传递的数据会报错 runtime-core.esm-bundler.js:268 Uncaught TypeError: Converting circular structure to JSON –> starting at object with constructor ‘Object’ — property ‘config’ closes the circle 原因…

HTTP,HTTPS

在网络工程师、开发工程师、运维工程师等岗位的面试中&#xff0c;​​HTTP/HTTPS​​ 是高频必考知识点&#xff0c;尤其在前端、后端、测试、DevOps等与网络通信相关的职位中。以下是系统化的核心考点梳理&#xff0c;涵盖基础概念、协议机制、安全特性及应聘高频问题。​​一…

Nginx访问日志分析在云服务器环境的技术实现与案例

在云计算时代&#xff0c;Nginx访问日志分析已成为服务器运维的关键环节。本文将深入解析如何通过日志切割、实时监控和可视化展示三大技术路径&#xff0c;实现云环境下Nginx日志的高效分析。我们将结合具体案例&#xff0c;演示从原始日志到运维决策的完整技术闭环&#xff0…

鸿蒙实现一次上传多张图片

记录初接触鸿蒙&#xff0c;遇到的一个问题&#xff0c;需求是点击一个图片上传的号图&#xff0c;访问本地图片&#xff0c;可以选择多张图片并上传。下面是图片上传后的方法&#xff1a;//选择图片并上传private async showPhotoPicker() {const maxImageCount 3;const rema…

【STM32】CRC 校验函数

先上一下 CRC校验 的源代码&#xff1a; void crc_check(unsigned char *ptr,unsigned int len) //crc为开源函数 {unsigned long wcrc0XFFFF;//预置16位crc寄存器&#xff0c;初值全部为1unsigned char temp;//定义中间变量int i0,j0;//定义计数for(i0;i<len;i)//循环计算每…