元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
设计原则
单一职责原则
开闭原则
里氏替换原则
依赖倒置原则
接口隔离原则
迪米特法则
▶
创建型模式
工厂方法模式
抽象工厂
单例模式
建造者模式
原型模式
▶
结构型模式
适配器模式
装饰器模式
代理模式
外观模式
组合模式
桥接模式
享元模式
▶
行为型模式
策略模式
观察者模式
命令模式
模板方法模式
状态模式
责任链模式
迭代器模式
中介者模式
访问者模式
备忘录模式
解释器模式
发布时间:
2025-03-21 15:22
↑
☰
# 备忘录模式 ## 概述 备忘录模式(Memento Pattern)是一种行为型设计模式,它允许在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。 ## 问题场景 在软件开发中,我们经常会遇到以下场景: 1. 需要保存对象的历史状态 2. 需要实现撤销/重做功能 3. 需要在不破坏封装的前提下保存对象状态 ## 解决方案 备忘录模式通过以下方式解决这些问题: ```mermaid classDiagram class Originator { -state +createMemento() +restoreMemento(Memento) } class Memento { -state +getState() } class Caretaker { -mementos +addMemento(Memento) +getMemento(index) } Originator --> Memento Caretaker o-- Memento ``` 主要角色: 1. 发起人(Originator): 创建并在需要时使用备忘录来恢复自身状态 2. 备忘录(Memento): 负责存储发起人的内部状态 3. 管理者(Caretaker): 负责保存备忘录,但不能对备忘录的内容进行操作或检查 ## 代码示例 ### 1. 基本实现 ```go // Memento 备忘录 type Memento struct { state string } func NewMemento(state string) *Memento { return &Memento{state: state} } func (m *Memento) GetState() string { return m.state } // Originator 发起人 type Originator struct { state string } func NewOriginator() *Originator { return &Originator{} } func (o *Originator) SetState(state string) { o.state = state } func (o *Originator) GetState() string { return o.state } func (o *Originator) CreateMemento() *Memento { return NewMemento(o.state) } func (o *Originator) RestoreMemento(memento *Memento) { o.state = memento.GetState() } // Caretaker 管理者 type Caretaker struct { mementos []*Memento } func NewCaretaker() *Caretaker { return &Caretaker{ mementos: make([]*Memento, 0), } } func (c *Caretaker) AddMemento(memento *Memento) { c.mementos = append(c.mementos, memento) } func (c *Caretaker) GetMemento(index int) *Memento { if index >= 0 && index < len(c.mementos) { return c.mementos[index] } return nil } ``` ### 2. 实际应用示例 ```go // 以文本编辑器为例 // EditorMemento 编辑器备忘录 type EditorMemento struct { content string cursorPosition int } func NewEditorMemento(content string, cursorPosition int) *EditorMemento { return &EditorMemento{ content: content, cursorPosition: cursorPosition, } } // TextEditor 文本编辑器 type TextEditor struct { content string cursorPosition int } func NewTextEditor() *TextEditor { return &TextEditor{} } func (e *TextEditor) Type(text string) { if e.cursorPosition == len(e.content) { e.content += text } else { e.content = e.content[:e.cursorPosition] + text + e.content[e.cursorPosition:] } e.cursorPosition += len(text) } func (e *TextEditor) MoveCursor(position int) { if position >= 0 && position <= len(e.content) { e.cursorPosition = position } } func (e *TextEditor) GetContent() string { return e.content } func (e *TextEditor) CreateMemento() *EditorMemento { return NewEditorMemento(e.content, e.cursorPosition) } func (e *TextEditor) RestoreMemento(memento *EditorMemento) { e.content = memento.content e.cursorPosition = memento.cursorPosition } // History 历史记录 type History struct { mementos []*EditorMemento currentIndex int } func NewHistory() *History { return &History{ mementos: make([]*EditorMemento, 0), currentIndex: -1, } } func (h *History) Push(memento *EditorMemento) { // 如果在历史记录中间进行了修改,删除当前位置之后的所有记录 if h.currentIndex < len(h.mementos)-1 { h.mementos = h.mementos[:h.currentIndex+1] } h.mementos = append(h.mementos, memento) h.currentIndex++ } func (h *History) Undo() *EditorMemento { if h.currentIndex > 0 { h.currentIndex-- return h.mementos[h.currentIndex] } return nil } func (h *History) Redo() *EditorMemento { if h.currentIndex < len(h.mementos)-1 { h.currentIndex++ return h.mementos[h.currentIndex] } return nil } // 使用示例 func main() { editor := NewTextEditor() history := NewHistory() // 初始状态 history.Push(editor.CreateMemento()) // 输入文本 editor.Type("Hello") history.Push(editor.CreateMemento()) editor.Type(" World") history.Push(editor.CreateMemento()) fmt.Println("Current:", editor.GetContent()) // Hello World // 撤销 if memento := history.Undo(); memento != nil { editor.RestoreMemento(memento) fmt.Println("After undo:", editor.GetContent()) // Hello } // 重做 if memento := history.Redo(); memento != nil { editor.RestoreMemento(memento) fmt.Println("After redo:", editor.GetContent()) // Hello World } } ``` ## 适用场景 1. 需要保存状态 - 需要保存对象的历史状态 - 需要支持撤销操作 2. 直接访问状态不可行 - 对象的状态信息必须私有 - 不能破坏对象的封装性 3. 快照功能 - 需要实现对象状态的快照 - 需要回滚功能 ## 优缺点 ### 优点 1. 提供状态恢复 - 可以恢复对象的历史状态 - 实现撤销/重做功能 2. 保持封装性 - 不破坏原对象的封装 - 状态信息保持私有 3. 简化原发器 - 状态保存的责任转移给备忘录 - 原发器更专注于业务逻辑 ### 缺点 1. 资源消耗 - 可能占用大量内存 - 需要存储多个状态副本 2. 维护成本 - 需要管理备忘录的生命周期 - 可能需要清理过期的备忘录 ## 实现要点 1. 状态存储 - 确定需要保存的状态 - 设计状态的存储结构 2. 访问权限 - 控制对状态的访问 - 保护状态的完整性 3. 资源管理 - 管理备忘录的数量 - 及时清理无用的备忘录 ## 相关模式 1. 命令模式 - 可以结合使用实现可撤销的操作 - 命令可以使用备忘录保存状态 2. 原型模式 - 可以用于创建备忘录 - 复制对象状态 3. 迭代器模式 - 可以用于遍历历史状态 - 访问备忘录集合 ## 总结 备忘录模式是一种用于保存和恢复对象状态的行为型设计模式,它的核心价值在于: 1. 状态管理 - 保存对象的历史状态 - 支持状态的恢复 2. 封装保护 - 不破坏对象的封装性 - 保护状态信息的私密性 3. 职责分离 - 分离状态管理的职责 - 使代码结构更清晰 在实际开发中,备忘录模式常用于需要实现撤销/重做功能的场景,如文本编辑器、绘图工具等。使用时需要注意状态存储的粒度和资源管理,避免过多的状态存储导致内存占用过大。