什么是备忘录模式?JavaScript 实现一个备忘录模式的示例
·
什么是备忘录模式?
备忘录模式(Memento Pattern)是一种行为型设计模式,它用于捕获一个对象的内部状态,并在不暴露对象实现细节的前提下,将状态保存起来,以便后续需要时恢复该对象到之前的状态。
其核心思想是:通过一个 “备忘录” 对象存储目标对象的状态,目标对象(原发器)负责创建和恢复备忘录,而 “负责人” 对象负责管理备忘录的存储和获取,从而实现状态的快照保存与回滚。
备忘录模式的核心角色
- 原发器(Originator):需要保存状态的对象,能创建备忘录(存储当前状态)和从备忘录恢复状态。
- 备忘录(Memento):存储原发器的内部状态,对外部(尤其是负责人)隐藏状态的具体结构,只允许原发器访问。
- 负责人(Caretaker):负责管理备忘录,提供保存(添加备忘录)和获取(检索备忘录)的接口,但不操作备忘录的内容。
JavaScript 实现备忘录模式示例:文本编辑器撤销功能
以下以 “文本编辑器” 为例,实现备忘录模式。场景是:用户在编辑器中输入文本时,系统会定期保存文本状态(快照),当用户点击 “撤销” 时,可恢复到上一次保存的状态。
代码实现
// -------------- 1. 备忘录(Memento):存储文本状态 --------------
class TextMemento {
/**
* 构造函数:存储原发器的状态
* @param {string} content - 文本内容
*/
constructor(content) {
this._content = content; // 私有属性(约定用下划线表示),仅允许原发器访问
}
/**
* 供原发器获取状态的方法(对外隐藏实现)
*/
getContent() {
return this._content;
}
}
// -------------- 2. 原发器(Originator):文本编辑器 --------------
class TextEditor {
constructor() {
this.content = ""; // 当前文本内容
}
/**
* 输入文本(修改状态)
* @param {string} text - 新增的文本
*/
type(text) {
this.content += text;
}
/**
* 创建备忘录(保存当前状态)
* @returns {TextMemento} 包含当前状态的备忘录
*/
save() {
return new TextMemento(this.content);
}
/**
* 从备忘录恢复状态
* @param {TextMemento} memento - 备忘录对象
*/
restore(memento) {
this.content = memento.getContent();
}
}
// -------------- 3. 负责人(Caretaker):管理备忘录(撤销历史) --------------
class HistoryManager {
constructor() {
this.mementos = []; // 存储备忘录的数组(撤销历史)
}
/**
* 保存备忘录(添加到历史)
* @param {TextMemento} memento - 备忘录对象
*/
push(memento) {
this.mementos.push(memento);
}
/**
* 获取上一个备忘录(用于撤销)
* @returns {TextMemento|null} 上一个状态的备忘录
*/
pop() {
return this.mementos.pop() || null;
}
}
// -------------- 4. 客户端使用 --------------
// 创建编辑器(原发器)和历史管理器(负责人)
const editor = new TextEditor();
const history = new HistoryManager();
// 操作1:输入文本并保存状态
editor.type("Hello, ");
history.push(editor.save()); // 保存状态1:"Hello, "
console.log("当前内容:", editor.content); // 输出:当前内容: Hello,
// 操作2:继续输入并保存
editor.type("World!");
history.push(editor.save()); // 保存状态2:"Hello, World!"
console.log("当前内容:", editor.content); // 输出:当前内容: Hello, World!
// 操作3:撤销(恢复到上一个状态)
const lastMemento = history.pop();
if (lastMemento) {
editor.restore(lastMemento);
console.log("撤销后内容:", editor.content); // 输出:撤销后内容: Hello, World!(此时历史中还剩状态1)
}
// 操作4:再次撤销(恢复到最初状态)
const firstMemento = history.pop();
if (firstMemento) {
editor.restore(firstMemento);
console.log("再次撤销后内容:", editor.content); // 输出:再次撤销后内容: Hello,
}
代码说明
-
备忘录(TextMemento):
- 存储文本编辑器的核心状态(
_content),通过getContent方法向原发器暴露状态,对负责人隐藏内部实现(如不允许负责人直接修改_content)。
- 存储文本编辑器的核心状态(
-
原发器(TextEditor):
type方法修改文本内容(状态变化)。save方法创建备忘录,将当前content存入备忘录。restore方法从备忘录中读取状态,恢复自身content。
-
负责人(HistoryManager):
- 用数组
mementos存储备忘录,提供push(保存)和pop(获取最近状态)方法。 - 不处理备忘录的内容,仅负责管理存储,避免直接访问原发器的内部状态。
- 用数组
-
核心优势:
- 状态封装:备忘录只允许原发器访问状态,保护了原发器的封装性(外部无法直接修改状态)。
- 可恢复性:通过保存的备忘录,可随时将对象恢复到历史状态(如编辑器的撤销功能)。
- 简化原发器:原发器无需自己管理历史状态,委托给负责人,符合 “单一职责原则”。
备忘录模式的常见应用场景
- 撤销 / 重做功能:如文本编辑器、图像编辑软件(PS 的历史记录)、表单填写(回退到上一步)。
- 快照备份:如数据库的事务回滚(保存事务执行前的状态)、游戏存档(保存当前游戏进度)。
- 状态日志:需要记录对象状态变化历史,以便追踪或审计的场景。
注意事项
- 内存开销:频繁保存备忘录可能占用大量内存(如长时间编辑的文档),可通过限制备忘录数量(如只保留最近 10 步)或压缩状态优化。
- 深拷贝需求:若原发器的状态包含引用类型(如对象、数组),备忘录需深拷贝状态,避免原发器修改后影响已保存的备忘录。
备忘录模式的核心是 “状态快照与安全恢复”,通过分离状态的创建、存储和恢复逻辑,实现了对象状态的灵活管理,是实现撤销、存档等功能的经典方案。
更多推荐



所有评论(0)