备忘录模式如何保存状态 对象状态恢复机制

备忘录模式通过在不破坏封装性的前提下保存并恢复对象状态来实现撤销等功能,1. 发起人创建包含当前状态的备忘录对象并返回给管理者;2. 管理者负责存储备忘录但无法访问其内容;3. 恢复时管理者将备忘录交还发起人,由发起人从中提取状态并重置自身;4. 备忘录通常采用深拷贝防止引用类型共享问题;5. 该模式适用于文本编辑器撤销、游戏存档、配置版本切换等场景,但需注意内存消耗与性能优化。

备忘录模式如何保存状态 对象状态恢复机制

备忘录模式(Memento Pattern)是一种行为型设计模式,它的核心作用是在不破坏封装性的前提下,保存对象的内部状态,并在之后恢复该状态。这种机制常用于实现撤销(Undo)、回滚、快照等功能。

一、备忘录模式如何保存对象状态

在备忘录模式中,对象状态的保存是通过一个中间对象——“备忘录”(Memento)来完成的。这个过程涉及三个关键角色:

发起人(Originator):需要保存状态的对象,它能创建一个包含当前状态的备忘录,也能通过备忘录恢复状态。备忘录(Memento):负责存储发起人的内部状态,通常将状态设为私有,仅允许发起人访问。管理者(Caretaker):负责保存和管理备忘录,但不能访问或修改备忘录内容。

状态保存流程如下:

发起人调用自身的

createMemento()

方法,将当前内部状态封装到一个新的备忘录对象中。备忘录对象创建时,会复制发起人当前的所有关键状态字段。发起人将备忘录返回给管理者,由管理者保存(例如存入列表、栈等)。

// 示例:Java 简化代码class Document {    private String content;    private String fontName;    private int fontSize;    public Memento createMemento() {        return new Memento(content, fontName, fontSize);    }    public void restore(Memento memento) {        this.content = memento.getContent();        this.fontName = memento.getFontName();        this.fontSize = memento.getFontSize();    }    // 内部类,仅对外暴露必要接口    public static class Memento {        private final String content;        private final String fontName;        private final int fontSize;        public Memento(String content, String fontName, int fontSize) {            this.content = content;            this.fontName = fontName;            this.fontSize = fontSize;        }        // 仅提供 getter,不提供 setter        public String getContent() { return content; }        public String getFontName() { return fontName; }        public int getFontSize() { return fontSize; }    }}

这样,状态被完整复制到备忘录中,而外部无法篡改,保证了封装性。

二、对象状态恢复机制是如何工作的

状态恢复是备忘录模式的另一核心功能。当需要回退到某个历史状态时,发起人从管理者处获取对应的备忘录,并用其数据覆盖当前状态。

恢复流程:

管理者从存储中取出某个备忘录(比如最近一次的、或指定版本的)。将该备忘录传回给发起人。发起人调用

restore(memento)

方法,用备忘录中的值重置自己的内部状态。

class History {    private final Stack mementos = new Stack();    public void push(Document.Memento memento) {        mementos.push(memento);    }    public Document.Memento pop() {        if (mementos.isEmpty()) return null;        return mementos.pop();    }}// 使用示例Document doc = new Document();History history = new History();doc.setContent("Hello");doc.setFontSize(12);history.push(doc.createMemento()); // 保存状态doc.setContent("World"); // 修改状态System.out.println(doc.getContent()); // 输出: WorldDocument.Memento m = history.pop();if (m != null) {    doc.restore(m); // 恢复}System.out.println(doc.getContent()); // 输出: Hello

这样就实现了“撤销”操作。管理者控制版本存储结构(栈、列表、树等),可以支持多级撤销或版本选择。

三、关键设计要点与注意事项

封装性保护:备忘录的内部状态应为私有,只有发起人能读取,防止外部误改。深拷贝 vs 浅拷贝:如果状态中包含引用类型(如集合、对象),需进行深拷贝,否则恢复时可能出错。性能与内存:频繁保存状态会占用较多内存,尤其在大数据对象或高频操作场景下。可结合快照策略(如定时保存、差量保存)优化。序列化替代方案:在某些语言中,可通过对象序列化+字节流存储实现类似功能,但牺牲了类型安全和性能。

四、典型应用场景

文本编辑器的撤销/重做功能游戏中的存档与读档数据库事务回滚的简化模型配置管理中的版本切换

基本上就这些。备忘录模式通过“快照+隔离访问”的方式,实现了安全、可控的状态保存与恢复,是实现撤销机制的经典解法。虽然实现略显繁琐,但在需要精确控制状态流转的场景中非常实用。

以上就是备忘录模式如何保存状态 对象状态恢复机制的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1470538.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月18日 18:26:20
下一篇 2025年12月18日 18:26:34

相关推荐

  • 深入理解Shadow DOM样式隔离:解决用户代理样式与继承冲突

    shadow dom的样式隔离特性导致全局%ignore_a_1%规则无法直接作用于其内部元素。特别是对于可继承属性,用户代理的默认样式可能覆盖外部继承值。本文将详细探讨shadow dom内样式冲突的原理,并提供两种主要解决方案:利用`inherit`关键字确保可继承属性正确传递,以及通过`ado…

    2025年12月23日
    000
  • 解决CSS Modules中Material-UI图标悬停效果不生效问题

    本文探讨了在react项目中使用css modules为material-ui图标应用悬停效果时可能遇到的问题。由于material-ui组件默认样式的高优先级,自定义的css modules规则可能无法生效。文章提供了一种有效的解决方案,通过结合`:global`语法和父选择器来提升css mod…

    2025年12月23日
    000
  • Shadow DOM 样式与布局机制深度解析

    本文深入探讨了web components中shadow dom的样式与布局机制。我们将解析shadow dom内部元素如何获取样式、可继承样式的作用、自定义元素默认的内联显示特性,以及内部块级元素(如` `)如何影响整体布局,并提供实际的代码示例和最佳实践,帮助开发者更好地掌握shadow dom…

    2025年12月23日
    000
  • 处理 Shadow DOM 中的样式隔离与用户代理样式优先级

    本文深入探讨了 shadow dom 环境下 css 样式的工作机制,特别是全局样式、可继承属性与用户代理样式之间的交互。文章将详细解释为何全局 `a` 标签样式无法直接渗透 shadow dom,以及如何通过 `color: inherit` 等策略有效管理 shadow dom 内部元素的样式,…

    2025年12月23日
    000
  • NextUI Navbar 背景颜色定制指南

    本教程详细介绍了如何在 nextui react 项目中自定义 navbar 组件的背景颜色。针对 nextui navbar 自动生成的 `nextui-navbar-container` 容器,文章提供了两种主要解决方案:通过覆盖 css 类或者利用 nextui 提供的 css 变量 `$$n…

    2025年12月23日
    000
  • 解决jQuery多计算器输入字段冲突的教程

    本文旨在解决在构建多功能计算器时,因jquery选择器重复使用导致计算结果不准确的问题。核心问题在于`$(‘.class’).val()`默认只获取匹配到的第一个元素的值。教程将详细阐述如何通过为每个计算逻辑的输入字段分配唯一的css类名来解决这一冲突,并提供完整的html和…

    2025年12月23日
    000
  • 掌握 CSS :has() 选择器:实现基于子元素的父元素样式联动

    本文将介绍如何利用 css 的 `:has()` 伪类选择器,在不直接引用父类名的情况下,根据子元素的存在来为父元素应用样式。这一强大的选择器解决了传统 css 无法从子元素反向选择父元素的限制,使得基于子元素状态的父元素样式联动成为可能。文章将通过示例代码详细演示其用法,帮助开发者高效实现复杂的布…

    2025年12月23日
    000
  • HTML5ShadowDOM怎么用_HTML5ShadowDOM实现组件封装的方法与原理

    Shadow DOM 是一种用于创建独立、封装 DOM 树的技术,通过 attachShadow 方法将影子 DOM 附加到元素上,实现样式和结构的隔离。其核心特性包括:样式作用域限制在 Shadow Root 内部,外部 CSS 难以影响内部结构;主文档的 DOM 查询无法直接访问影子节点;结合 …

    2025年12月23日
    000
  • PHP ArgumentCountError 解决方案:正确定义与调用类方法

    本文旨在解决 php 开发中常见的 `argumentcounterror: too few arguments` 错误,特别是当类方法(如获取器 getter)在定义时错误地包含了不必要的参数,而在调用时未提供这些参数导致的问题。我们将深入分析错误原因,并提供简洁有效的解决方案,通过优化方法签名来…

    2025年12月23日
    000
  • 在ASP.NET MVC视图中动态替换URL语言代码

    本文旨在提供一种在ASP.NET MVC视图中动态替换URL路径中语言代码的专业方法。通过在`.cshtml`文件中定义一个C#辅助函数,结合正则表达式的精确匹配能力,可以安全有效地将URL路径中的当前语言代码替换为新的语言代码,避免了简单字符串替换可能导致的意外副作用,从而增强了多语言网站的用户体…

    2025年12月23日
    000
  • 解决PrimeNG p-password组件宽度自适应问题

    PrimeNG的p-password组件在布局中可能无法自动适配父容器宽度,即使使用了PrimeFlex的w-full类也可能失效。本文将深入分析p-password组件的内部结构和样式机制,提供通过[style]和[inputStyle]属性精确控制组件及其内部输入框宽度的方法,确保组件能完美融入…

    2025年12月23日
    000
  • Sass模块化开发:如何有效拆分SCSS文件并统一编译

    本教程详细讲解如何通过sass的模块化特性,将大型scss文件拆分为多个可维护的局部文件(partials),并利用`@import`规则将它们统一编译成单个css文件。这有助于提高代码组织性、降低维护难度,并避免冗长样式表的出现。文章还将提及`@use`与`@import`的选择考量。 在大型We…

    2025年12月23日
    100
  • 使用Sass拆分CSS文件以提高可维护性

    本文介绍了如何将大型Sass文件拆分成多个更小、更易于管理的模块,并通过`@import`指令将它们组合成一个最终的CSS文件。这种方法可以显著提高代码的可维护性,尤其是在大型项目中。 在大型Web项目中,将所有CSS样式都放在一个文件中会导致文件变得非常庞大,难以维护和管理。Sass提供了一种有效…

    2025年12月23日
    000
  • JavaScript模块函数在HTML中调用的时序陷阱与解决方案

    本文探讨了在html页面中调用通过`type=”module”`导入的javascript模块函数时常见的`referenceerror: t is not defined`错误。核心问题在于脚本加载和执行的时序。文章将详细解释为何直接调用会失败,并提供使用`onload`事…

    2025年12月23日
    000
  • 解决Cypress无法定位Shadow DOM中表单元素的问题

    本文旨在解决cypress测试中因shadow dom导致元素定位失败的问题。当传统dom选择器无法找到页面元素时,通常是因为这些元素被封装在shadow dom内部。教程将详细解释shadow dom的概念,并提供使用cypress的`.shadow()`命令来正确访问和操作这些隐藏元素的解决方案…

    2025年12月23日
    000
  • CSS/React:实现图片悬停显示多个按钮的交互教程

    本教程详细探讨了在react项目中,如何利用css实现图片悬停时同时显示多个交互按钮的常见需求。文章首先分析了css相邻兄弟选择器`+`的局限性,进而介绍了通用兄弟选择器`~`的正确用法,以及更推荐的通过父元素悬停触发子元素显示的高效策略。通过具体的代码示例和最佳实践,帮助开发者构建响应式且用户友好…

    2025年12月23日 好文分享
    000
  • Cypress与Shadow DOM:如何正确选取隐藏在阴影DOM中的元素

    cypress在测试web组件时,常因元素位于shadow dom内部而无法定位。本文旨在解决这一常见问题,详细阐述如何利用cypress的`.shadow()`命令,结合正确的shadow host选择器,有效穿透shadow dom边界,精准定位并操作其中的表单元素,确保测试的准确性和稳定性。 …

    2025年12月23日
    000
  • Cypress中Shadow DOM元素定位策略:解决元素查找失败问题

    本文旨在解决cypress测试中因shadow dom导致元素查找失败的问题。我们将深入探讨shadow dom的特性及其对自动化测试的影响,并详细介绍如何利用cypress提供的`.shadow()`命令,结合正确的选择器策略,精准定位并操作shadow dom内部的元素,确保测试脚本的稳定性和可…

    2025年12月23日
    000
  • Cypress 测试中 Shadow DOM 元素定位策略与实践

    本文详细阐述了在 cypress 测试中,当目标元素位于 shadow dom 内部时,标准选择器失效的原因及解决方案。教程将指导读者如何识别 shadow host 并利用 cypress 的 `.shadow()` 命令,有效定位并与 shadow dom 中的表单元素进行交互,确保测试的准确性…

    2025年12月23日
    000
  • Web Components Shadow DOM与浏览器自动填充的兼容性挑战

    当输入框位于web components的shadow dom内部时,浏览器的自动填充(autofill)功能常常无法按预期工作。尽管html的`autocomplete`属性在原生输入框中表现良好,但在shadow dom中,浏览器难以识别和关联这些输入框,导致用户体验受损。这是一个已知的功能缺失…

    2025年12月23日
    000

发表回复

登录后才能评论
关注微信