ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

备忘录模式(Memento Pattern)

2026/8/4 9:35:32 拓冰建站 浏览量
备忘录模式(Memento Pattern)

备忘录模式(Memento Pattern)

1. 知识点总结

备忘录模式是一种行为型设计模式,核心思想是:

在不破坏对象封装性的前提下,捕获对象的内部状态并保存在外部,以便后续能够将对象恢复到之前的状态。

它最常见的应用就是撤销(Undo)/重做(Redo)功能,比如文本编辑器、游戏存档、数据库事务回滚等。

模式中有三个核心角色:

角色 职责
Originator(发起人) 拥有需要保存的状态,提供创建备忘录和恢复状态的方法
Memento(备忘录) 封装 Originator 的内部状态,对外隐藏细节
Caretaker(管理者) 负责保存和恢复备忘录,不直接操作备忘录内容

适用场景

  • 需要实现撤销/重做功能;
  • 需要保存对象的历史快照,支持回滚;
  • 事务执行失败时需要还原到执行前的状态。

优缺点

优点 缺点
不破坏封装性,外部无法随意修改备忘录状态 频繁保存大对象会消耗较多内存
状态保存逻辑与业务逻辑分离 管理者需要维护备忘录集合,可能引入额外复杂度
容易实现多步撤销/重做 需要谨慎处理深拷贝与浅拷贝问题

2. 示例代码

下面用一个简单的文本编辑器来演示:每次写入后保存快照,误操作后可以通过历史栈撤销。

package mainimport "fmt"// Editor 是发起人(Originator),拥有需要被保存的内部状态。
type Editor struct {content string
}func (e *Editor) Write(text string) {e.content += text
}func (e *Editor) Content() string {return e.content
}// Save 创建一份备忘录,封装当前内容。
func (e *Editor) Save() Memento {return Memento{snapshot: e.content}
}// Restore 根据备忘录恢复状态。
func (e *Editor) Restore(m Memento) {e.content = m.snapshot
}// Memento 是备忘录,只暴露给 Caretaker 和 Originator 使用。
// 这里通过未导出字段限制外部直接修改快照内容。
type Memento struct {snapshot string
}// History 是管理者(Caretaker),负责维护备忘录的历史栈。
type History struct {stack []Memento
}func (h *History) Save(m Memento) {h.stack = append(h.stack, m)
}func (h *History) Undo() (Memento, bool) {if len(h.stack) == 0 {return Memento{}, false}last := h.stack[len(h.stack)-1]h.stack = h.stack[:len(h.stack)-1]return last, true
}func main() {editor := &Editor{}history := &History{}editor.Write("Hello ")history.Save(editor.Save())fmt.Printf("写入后: %q\n", editor.Content())editor.Write("World!")history.Save(editor.Save())fmt.Printf("再次写入后: %q\n", editor.Content())editor.Write(" 这是多余内容")fmt.Printf("误操作后: %q\n", editor.Content())if m, ok := history.Undo(); ok {editor.Restore(m)fmt.Printf("撤销一次后: %q\n", editor.Content())}if m, ok := history.Undo(); ok {editor.Restore(m)fmt.Printf("再撤销一次后: %q\n", editor.Content())}
}

3. 运行结果

写入后: "Hello "
再次写入后: "Hello World!"
误操作后: "Hello World! 这是多余内容"
撤销一次后: "Hello World!"
再撤销一次后: "Hello "

4. 关键点复盘

  1. 封装性是第一原则:备忘录的 snapshot 字段没有导出,外部(包括 Caretaker)不能直接修改快照内容,只能通过 Originator 的 Save/Restore 来操作。
  2. Caretaker 只负责保管History 不知道备忘录里具体存了什么,也不应该去解析它,这样 Originator 的内部结构变化不会影响历史管理逻辑。
  3. 栈是实现撤销的常用结构:每次保存时入栈,撤销时出栈并恢复;如果要支持重做,可以再加一个 redo 栈。
  4. 注意深拷贝:如果 Originator 的状态包含引用类型(切片、Map、指针),保存备忘录时需要进行深拷贝,否则快照会被后续修改污染。
  5. 与命令模式的区别:备忘录模式通过保存状态快照来撤销;命令模式通常通过记录逆操作来撤销。状态简单时用备忘录更直接,操作复杂时命令模式更灵活。