备忘录模式(Memento Pattern)详解

前一篇文章解锁时光机用到了备忘录模式,那么什么是备忘录模式?

备忘录模式是一种行为型设计模式,它的核心思想是在不暴露对象内部细节的情况下,捕获并保存一个对象的内部状态,以便在将来可以恢复到这个状态

这个模式就像一个"时光机",能够让你在程序运行时记录下某个时刻的状态,并在需要时"穿越"回去。

核心角色

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

  1. 发起人(Originator)

    • 这是需要被保存状态的对象。
    • 它负责创建一个备忘录(Memento),来保存自己的当前状态。
    • 它也能够使用备忘录来恢复到之前的状态。
    • 在我们的 React 例子中,reducer 函数和其中的 state 对象就是发起人。它能创建和恢复状态。
  2. 备忘录(Memento)

    • 这是用于存储发起人内部状态的快照对象。
    • 它提供一个受限的接口,只允许发起人访问其内部状态。外部对象(比如 caretaker)无法直接修改备忘录的内容,只能将其作为"黑盒子"传递。
    • 在我们的 React 例子中,pastfuture 数组中的每一个 present 值,就是一个备忘录。它是一个简单的数值,不需要复杂的对象来封装。
  3. 管理者(Caretaker)

    • 负责保存和管理备忘录。
    • 它不知道备忘录内部的具体细节,只知道备忘录是从发起人那里来的,并能在需要时将它还给发起人。
    • 它不能对备忘录的内容进行任何操作,只能存储和检索。
    • 在我们的 React 例子中,state 对象中的 pastfuture 数组就是管理者reducer 函数负责将备忘录(即状态值)放入或取出这些数组。

工作流程

  1. 保存状态 :发起人(Originator)在需要时,创建一个备忘录(Memento),将自己的当前状态保存进去。然后将这个备忘录交给管理者(Caretaker)。
  2. 恢复状态 :当需要恢复时,管理者(Caretaker)将之前保存的备忘录交给发起人(Originator)。发起人通过备忘录中的信息,将自己的状态恢复到之前的样子。

备忘录模式与代码示例

现在,让我们把这些角色对应到代码中,一切就变得清晰了:

  • 发起人(Originator) : state 对象中的 present 值。它代表了当前的核心状态。
  • 备忘录(Memento) : pastfuture 数组中的每一个数值。每个数值都是一个"状态快照"。
  • 管理者(Caretaker) : state 对象中的 pastfuture 数组。它们负责存储这些状态快照。

具体实现流程:

  1. Increment 操作

    • Originatorpresent)的状态即将改变。
    • Originator 告诉 Caretakerpast 数组),"我马上要变了,这是我现在的样子,你帮我存一下。"
    • Caretaker 将当前的 present[...past, present] 存入 past 数组。
  2. Undo 操作

    • Caretakerpast 数组)将最后一个备忘录(past.at(-1))交给 Originator
    • Originator 接收这个备忘录,并将其恢复为自己的状态(present: past.at(-1))。
    • 同时,Originator 将当前状态作为新的备忘录,交给另一个 Caretakerfuture 数组),以便重做。

为什么这种模式更优越?

备忘录模式的优点在于它实现了解耦 。管理者(past/future 数组)和发起人(present 值)之间只需要知道如何存取备忘录,而不需要知道备忘录内部的具体结构或如何改变状态。这意味着你可以轻松地改变 incrementdecrement 的逻辑,而 undoredo 的逻辑完全不需要改动。

这就是为什么代码二的设计如此优雅和可扩展。它不关心"如何"改变,只关心"改变前"和"改变后"的状态是什么,并将这些状态作为备忘录保存起来。

相关推荐
陈随易8 小时前
有生之年系列,Nodejs进程管理pm2 v7.0发布
前端·后端·程序员
冰暮流星8 小时前
javascript之事件代理/事件委托
前端
陈随易10 小时前
AI时代,你还在坚持手搓文章吗
前端·后端·程序员
里欧跑得慢12 小时前
17. Flutter Hero动画实现:让界面过渡更加优雅
前端·css·flutter·web
IT_陈寒12 小时前
Vue的这个响应式陷阱,我debug了一整天才爬出来
前端·人工智能·后端
kyriewen12 小时前
前端测试:别为了100%覆盖率而写测试,那是自欺欺人
前端·javascript·单元测试
去伪存真13 小时前
我自己写的第一个skills--project-core-standards
前端·agent
Data_Journal13 小时前
如何使用cURL更改User Agent
大数据·服务器·前端·javascript·数据库
竹林81813 小时前
wagmi v2 多链钱包切换:一个 Uniswap 仿盘项目让我踩了三天坑
前端·javascript
donecoding13 小时前
Playwright MCP 页面捕获:Snapshot、截图、HTML 到底选哪个?
前端·ai编程·前端工程化