惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
Simon Willison's Weblog
Simon Willison's Weblog
H
Help Net Security
F
Fortinet All Blogs
H
Heimdal Security Blog
S
Schneier on Security
L
LangChain Blog
博客园 - Franky
酷 壳 – CoolShell
酷 壳 – CoolShell
NISL@THU
NISL@THU
P
Palo Alto Networks Blog
J
Java Code Geeks
博客园 - 【当耐特】
The Last Watchdog
The Last Watchdog
W
WeLiveSecurity
www.infosecurity-magazine.com
www.infosecurity-magazine.com
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Vulnerabilities – Threatpost
I
InfoQ
Recorded Future
Recorded Future
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
CERT Recently Published Vulnerability Notes
T
Tenable Blog
腾讯CDC
C
Check Point Blog
量子位
M
MIT News - Artificial intelligence
GbyAI
GbyAI
罗磊的独立博客
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
B
Blog
小众软件
小众软件
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CXSECURITY Database RSS Feed - CXSecurity.com
Stack Overflow Blog
Stack Overflow Blog
P
Proofpoint News Feed
P
Privacy & Cybersecurity Law Blog
V2EX - 技术
V2EX - 技术
T
Threatpost
Engineering at Meta
Engineering at Meta
Attack and Defense Labs
Attack and Defense Labs
T
Tailwind CSS Blog
S
Securelist
The Cloudflare Blog
博客园 - 叶小钗
L
LINUX DO - 最新话题
T
Troy Hunt's Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
爱范儿
爱范儿

半方池水半方田

小球称重问题及其引申的思考 蓝色的结构色 病毒是不是生物? 把博客发布交给 GitHub Actions 省外居民身份证的补换领(苏州) hexo-filter-titlebased-link:构建你的数字花园 Vercel 应用实践学习 通过与 Keycloak 配合实现博客文章的受限访问功能 非公开的文章 Soft Mode 非公开的文章 Strict Mode 试试用代码块在 Hexo 中插入实况照片 动态图片测试 Hexo-Butterfly 主题 Preloader 加载页定制 Keycloak 的部署以及 Hexo-Butterfly 网页应用的接入 随机访问文章的实现(Sitemap+本地缓存优化) Authentik 的部署记录 Waline 自建 Auth 认证 记一次行李托运理赔流程(南航) Docker 镜像的制作、拉取与运行 Hexo-Butterfly 主题中对 Algolia 搜索框 Power By 的定制 Hexo 动态加载配置(钩子函数) 设计原则 VSCode 中的配置 Spring AI 中使用 PGVector 实现向量存储 提示词工程速查手册 2025 WePlay 上海两日游 和随机数生成相关的题目 一起撸串(字符串) 树状数组上手了就十分简单 缓存置换算法的实现与 Java 中相关的数据结构 关于海量数据的若干问题 访问者模式填补单分派语言的缺陷
备忘录模式:拍下照片
wuanqin · 2025-08-30 · via 半方池水半方田

备忘录模式:拍下照片

|总字数:1.8k|阅读时长:5分钟|浏览量:|

|出链:4|入链:3

image.png

备忘录模式/快照模式 Memento Design Pattern

Captures and externalizes an object’s internal state so that it can be restored later, all without violating encapsulation.——GoF
在不违背封装原则的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便之后恢复对象为先前的状态。

image.png

备忘录模式可以实现的功能:

  • Undo(撤销)
  • Redo(重做)
  • History(历史记录)
  • Snapshot(快照)

备忘录模式的实现很灵活,也没有很固定的实现方式,在不同的业务需求、不同编程语言下,代码实现可能都不大一样。

image.png

注意:

  • OriginatorMemento 不是父子关系。
  • Caretaker 无法 newMemento 实例,只能通知 Originatornew
  • 为了实现访问权限控制,注意 OriginatorMemento 的包的关系。
1
2
3
4
5
6
7
8
9
10
class Originator{
public Memento createMemento(){
Memento memento=new Memento();

return memento;
}
public void restoreMemento(Memento memento){

}
}

登场角色:

  • Originator(原发器):Originator 角色会在保存自己的最新状态时生成 Memento 角色。当把以前保存的 Memento 角色传递给 Originator 角色时,它会将自己恢复至生成该 Memento 角色时的状态。
  • Memento(备忘录):
    • Originator 角色和 Memento 角色之间有着非常紧密的联系。Memento 角色会将 Originator 角色的内部信息整合在一起。
    • Memento 角色中虽然保存了 Originator 角色的信息,但它不会向外部公开这些信息。Memento 角色有以下两种接口(API)以防止对象的封装性被破坏:
      • 宽接口(API)——Wide interface。Memento 角色提供的「宽接口(API)」是指所有用于获取恢复对象状态信息的方法的集合。由于宽接口(API)会暴露所有 Memento 角色的内部信息,因此能够使用宽接口(API)的只有 Originator 角色。
      • 窄接口(API)——Narrow interface。Memento 角色为外部的 Caretaker 角色提供了「窄接口(API)」。可以通过窄接口(API)获取的 Memento 角色的内部信息非常有限,因此可以有效地防止信息泄露。
  • Caretaker(负责人):当 Caretaker 角色想要保存当前的 Originator 角色的状态时,会通知 Originator 角色。Originator 角色在接收到通知后会生成 Memento 角色的实例并将其返回给 Caretaker 角色。
    • 负责人仅知道「何时」和「为何」捕捉原发器的状态,以及何时恢复状态。
    • 由于以后可能会用 Memento 实例来将 Originator 恢复至原来的状态,因此 Caretaker 角色会一直保存 Memento 实例。不过,Caretaker 角色只能使用 Memento 角色的窄接口(API),也就是说它无法访问 Memento 角色内部的所有信息。它只是将 Originator 角色生成的 Memento 角色当作一个黑盒子保存起来。
    • 虽然 Originator 角色和 Memento 角色之间是强关联关系,但 Caretaker 角色和 Memento 角色之间是弱关联关系。Memento 角色对 Caretaker 角色隐藏了自身的内部信息。

适用于不支持嵌套类的编程语言的实现方法

比如 PHP 语言。
image.png

  1. 在没有嵌套类的情况下, 你可以规定负责人仅可通过明确声明的中间接口与备忘录互动, 该接口仅声明与备忘录元数据相关的方法, 限制其对备忘录成员变量的直接访问权限。
  2. 另一方面, 原发器可以直接与备忘录对象进行交互, 访问备忘录类中声明的成员变量和方法。 这种方式的缺点在于你需要将备忘录的所有成员变量声明为公有。

封装更加严格的实现

image.png

  1. 这种实现方式允许存在多种不同类型的原发器和备忘录。 每种原发器都和其相应的备忘录类进行交互。 原发器和备忘录都不会将其状态暴露给其他类。
  2. 负责人此时被明确禁止修改存储在备忘录中的状态。 但负责人类将独立于原发器, 因为此时恢复方法被定义在了备忘录类中。
  3. 每个备忘录将与创建了自身的原发器连接。 原发器会将自己及状态传递给备忘录的构造函数。 由于这些类之间的紧密联系, 只要原发器定义了合适的设置器 (setter), 备忘录就能恢复其状态。

拓展思路:

  • 两种接口(API)的可见性。控制访问权限。
  • 可以实现保存多个 Memento,这样就可以保存各个时间点的状态。
  • 注意 Memento 的有效期。
  • Caretaker 决定何时拍照,何时撤销以及保存 Memento 角色。Originator 角色的职责是生成 Memento 角色和使用接收到的 Memento 角色来恢复自己的状态。这样的职责分担,当遇到以下需求时,Originator 不用改变:
    • 可以多次撤销
    • 不仅可以多次撤销,还可以将现在的状态保存在文件中
优点 缺点
可以在不破坏对象封装情况的前提下创建对象状态快照。 如果客户端过于频繁地创建备忘录,程序将消耗大量内存。
可以通过让负责人维护原发器状态历史记录来简化原发器代码。 负责人必须完整跟踪原发器的生命周期,这样才能销毁弃用的备忘录。
绝大部分动态编程语言(例如 PHP、Python 和 JavaScript)不能确保备忘录中的状态不被修改。

备忘录模式与「备份」的概念区别:

  • 这两者的应用场景很类似,都应用在防丢失、恢复、撤销等场景中。
  • 备忘录模式更侧重于代码的设计和实现;备份更侧重架构设计或产品设计。

使用「低频率全量备份」和「高频率增量备份」方式可以优化内存和时间消耗。

image.png

相关的设计模式:

  • 站内文章命令模式:在使用命令模式处理命令时,可以使用备忘录模式实现撤销功能。
  • 站内文章原型模式:在备忘录模式中,为了能够实现快照和撤销功能,保存了对象当前的状态。保存的信息只是在恢复状态时所需要的那部分信息。而在原型模式中,会生成一个与当前实例完全相同的另外一个实例。这两个实例的内容完全一样。
  • 站内文章状态模式:在备忘录模式中,是用「实例」表示状态。而在状态模式中,则是用「类」表示状态。
  • 站内文章迭代器模式:可以同时使用备忘录和迭代器模式来获取当前迭代器的状态,并且在需要的时候进行回滚。

本文参考

版权声明 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 半方池水半方田

赞助

  • 微信

    微信

  • 支付宝

    支付宝


avatar

wuanqin

只能懂一点点

最新文章

蓝色的结构色