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

备忘录模式通过在不破坏封装性的前提下保存并恢复对象状态来实现撤销等功能,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月8日 06:51:33

相关推荐

  • C++中static关键字有哪些作用 局部变量类成员和函数用法

    static++在c++中用于改变变量、函数及类成员的行为,主要有四个用途:1.修饰局部变量时延长其生命周期至整个程序运行期间,但作用域不变;2.修饰类成员变量实现数据共享,所有对象共用一份副本,需类外初始化;3.修饰类成员函数使其只能访问静态成员,无this指针,与对象无关;4.修饰全局函数或变量…

    2025年12月18日 好文分享
    000
  • C++结构体如何定义和使用 struct与class异同点解析

    在 c++++ 中,struct 和 class 的主要区别在于默认访问权限。struct 默认成员是 public,而 class 默认成员是 private;除此之外,两者在功能上几乎完全相同,均支持成员变量、成员函数、继承、访问修饰符等面向对象特性。定义结构体使用 struct 关键字,适合表…

    2025年12月18日 好文分享
    000
  • C++20对智能指针有哪些改进 新特性和使用模式更新

    c++++20并未引入新智能指针类型,但通过增强现有功能提升安全性与效率。1. 扩展constexpr支持,使智能指针可用于编译期场景,建议标记构造函数为constexpr并确保删除器兼容。2. 优化shared_ptr多线程性能并支持原子操作,建议使用std::atomic_store等函数避免手…

    2025年12月18日 好文分享
    000
  • 如何用智能指针管理第三方库资源 自定义删除器实践案例

    标准智能指针无法直接管理所有第三方库资源的原因是它们默认使用delete操作符释放资源,而第三方库通常需要特定的销毁函数。1. 第三方库资源如c库内存(malloc/free)、文件句柄(fopen/fclose)或图形库api(create_texture/destroy_texture)需用对应…

    2025年12月18日 好文分享
    000
  • C++备忘录模式如何实现对象状态保存 序列化与恢复机制

    备忘录模式是一种行为型设计模式,其核心在于在不破坏封装性的前提下捕获并外部化对象内部状态,以便之后可恢复该状态。1. 它包含三个核心角色:发起人(originator)负责创建和恢复状态;备忘录(memento)存储状态且对外隐藏实现细节;管理者(c++aretaker)保存备忘录但不查看其内容。2…

    2025年12月18日 好文分享
    000
  • 结构体继承是否可行 对比C++继承与C风格组合模式

    c++++支持结构体继承,允许派生结构体继承基结构体的成员;c语言不支持继承,但可通过结构体组合实现类似效果。1. c++继承优势在于代码复用和多态性,可直接使用基类功能并实现不同行为;2. 局限性包括紧耦合、菱形继承问题及封装性破坏;3. c风格组合通过结构体嵌套实现松耦合,修改结构体不影响其他结…

    2025年12月18日 好文分享
    000
  • STL函数对象有什么优势 对比函数指针和lambda表达式

    函数对象在c++++ stl中具有状态携带能力和更高性能,首先,它能保存调用间的状态,如counter统计正整数个数,而函数指针需依赖全局或静态变量,破坏封装性;其次,函数对象调用是静态绑定,更易被编译器内联优化,性能优于动态绑定的函数指针,尤其适用于性能敏感场景;第三,lambda表达式在底层被转…

    2025年12月18日 好文分享
    000
  • C++成员函数指针怎么使用 回调机制与事件系统实现方式

    在c++++中,成员函数指针适合用于回调机制和事件系统,因为它需绑定对象实例调用。1. 成员函数指针基本语法为void (myclass::*ptr)(int) = &myclass::func;,调用时必须通过对象实例使用.*或->*运算符;2. 回调机制中常用静态“跳板”函数将成员…

    2025年12月18日 好文分享
    000
  • C++如何实现动态多维数组 指针与容器类的选择策略

    在c++++中实现动态多维数组的常见方式有指针和std::vector;1. 使用指针可手动控制内存,适用于极致性能优化和底层开发,但易出错且维护困难;2. 使用std::vector自动管理内存,提升代码安全性和可维护性,适合大多数现代项目;3. 选择依据包括性能需求、开发场景及团队协作等因素,二…

    2025年12月18日 好文分享
    000
  • 如何重载运算符?使用operator关键字定义

    运算符重载是c++++中赋予已有运算符新含义的技术,例如让复数对象用+相加。实现时需用operator关键字定义函数,如complex operator+(const complex& a, const complex& b); 重载可作为成员函数或全局函数实现,前者适合访问内部数据…

    2025年12月18日 好文分享
    000
  • 结构体数组怎样定义和使用 批量处理结构体数据实例演示

    结构体数组是将多个结构体实例排列成集合的数据结构,它允许存储和管理具有多种属性的同类数据记录。1. 定义时需先声明结构体类型,再创建数组;2. 初始化可逐个赋值或在定义时指定初始值;3. 使用时通过索引访问结构体成员并进行批量处理;4. 与普通数组的区别在于每个元素是一个包含多种数据类型的结构体,而…

    2025年12月18日 好文分享
    000
  • 类的访问修饰符有哪些?public、private和protected

    访问修饰符用于控制类成员的可访问范围,主要分为 public、private 和 protected。public 允许任何地方访问,适用于对外暴露的方法或属性;private 仅允许在定义它的类内部访问,常用于保护数据并配合 getter/setter 使用;protected 允许同一包内访问及…

    2025年12月18日
    000
  • 如何创建C++银行账户系统 类与对象的基础应用实例

    如何创建一个c++++银行账户系统?1.定义bankaccount类封装账号、户名和余额等属性,并提供存款、取款、查询等公共方法;2.使用构造函数初始化账户信息,通过deposit和withdraw方法实现金额操作并包含合法性校验;3.在main函数中利用vector容器管理多个账户对象,支持账户的…

    2025年12月18日 好文分享
    000
  • C++运算符重载有哪些限制 友元函数与成员函数重载的区别

    c++++运算符重载存在明确限制和选择标准。1. 不可重载的运算符包括:.(成员访问)、.*(成员指针访问)、::(作用域解析)、?:(条件)、sizeof、typeid及所有类型转换运算符,因其关联语言核心机制。2. 重载时需选择成员函数或友元函数:成员函数适用于一元运算符、左操作数固定为类对象的…

    2025年12月18日 好文分享
    000
  • 如何理解C++20的modules特性 替代头文件包含的新编译模型

    c++++20 modules通过模块化编译模型提升编译效率并解决命名空间污染问题。1. 它将模块编译为二进制接口文件(bmi),实现“一次编译,多次使用”,减少重复解析,显著提升大型项目编译速度,并支持更优的并行编译;2. 通过显式导出接口,隐藏内部实现,仅暴露必要声明,避免头文件引入导致的命名冲…

    2025年12月18日 好文分享
    000
  • C++中的友元机制是什么 打破封装访问私有成员的方法

    友元机制在c++++中用于允许特定函数或类访问另一个类的私有和受保护成员。1. 友元函数不是类的成员,但可通过friend关键字声明以访问类的私有数据;2. 友元类的所有成员函数均可访问目标类的私有成员,关系单向;3. 使用时应避免滥用、控制访问范围、注意不可继承及非对称性;4. 常见应用场景包括运…

    2025年12月18日 好文分享
    000
  • 怎样应用C++的访问控制 合理使用public protected private

    默认私有化是c++++类设计的黄金法则,因为它强制信息隐藏、防止不当使用并明确接口契约。1. 信息隐藏通过将实现细节设为private,使外部无法直接依赖,降低耦合;2. 防止对象状态被随意修改,确保数据一致性;3. 明确public接口作为类与外界交互的唯一通道,提升模块化和可维护性。protec…

    2025年12月18日 好文分享
    000
  • C++11如何简化数组操作 std array容器与传统数组对比

    std::array 是 c++++11 引入的固定大小容器,定义在 头文件中,是对传统数组的封装并具备如下优势:1. 可直接赋值;2. 支持迭代器和范围 for 循环;3. 可结合 .at() 方法进行越界检查;4. 可作为函数参数完整传递;5. 性能与原生数组相当,无额外开销;建议用于固定大小数…

    2025年12月18日 好文分享
    000
  • 什么是placement new操作符 特定内存位置构造对象技术

    placement new与标准new的核心区别在于职责分离。1. 标准new负责内存分配与构造对象,而placement new仅调用构造函数,不分配内存;2. 使用placement new时需手动管理内存生命周期,包括显式调用析构函数和释放原始内存;3. 它适用于需要精细内存控制的场景,如内存…

    2025年12月18日 好文分享
    000
  • C++如何实现备忘录模式 C++备忘录模式的设计

    备忘录模式是一种保存和恢复对象状态的设计模式,其核心在于通过备忘录类存储对象状态,发起人类负责创建和恢复状态,管理者类用于管理多个备忘录。1. 使用模板实现通用备忘录类,避免类型限制;2. 采用智能指针(如 std::shared_ptr)管理内存,防止内存泄漏;3. 注意深拷贝对象状态,确保备忘录…

    2025年12月18日 好文分享
    000

发表回复

登录后才能评论
关注微信