【再谈设计模式】备忘录模式~对象状态的守护者
- 手机
- 2025-09-18 05:24:02

一、引言
在软件开发过程中,我们常常会遇到需要保存对象状态以便在之后恢复的情况。例如,在文本编辑器中,我们可能想要撤销之前的操作;在游戏中,玩家可能希望恢复到之前的某个游戏状态。备忘录模式(Memento Pattern)就为这种需求提供了一种有效的解决方案。
二、定义与描述
备忘录模式属于行为型设计模式。它的主要目的是在不破坏对象封装性的前提下,捕获并外部化一个对象的内部状态,以便之后可以将该对象恢复到这个状态。这个模式涉及到三个主要角色:
原发器(Originator):创建一个备忘录,用于记录当前时刻它的内部状态。原发器还可以使用备忘录来恢复其内部状态。
备忘录(Memento):存储原发器对象的内部状态。备忘录应该防止原发器以外的其他对象访问其内部状态。
负责人(Caretaker):负责保存备忘录,但不能对备忘录的内容进行操作或检查。
三、抽象背景
在许多应用场景中,对象的状态会随着时间发生变化。然而,我们可能需要在某个特定的时间点保存对象的状态,以便后续可以撤销操作或者回到之前的某个状态。如果直接将对象的状态暴露给外部进行保存和恢复,会破坏对象的封装性。备忘录模式通过引入一个专门的备忘录对象来解决这个问题,使得对象的状态可以在不破坏封装性的情况下被保存和恢复。
四、适用场景与现实问题解决 (一)适用场景
文本编辑器的撤销/重做功能:当用户输入文字、删除文字或者进行格式调整时,每一个操作都可以看作是对象(文本内容)状态的改变。通过备忘录模式,可以轻松地保存每个操作前的文本状态,从而实现撤销和重做功能。
游戏中的存档和读档功能:游戏中的各种元素(角色属性、游戏场景等)构成了对象的状态。玩家在游戏过程中可能希望在某些关键节点保存游戏状态,之后可以随时读取之前保存的状态继续游戏。
(二)现实问题解决以文本编辑器为例,假设我们有一个TextDocument类作为原发器。在用户进行编辑操作(如插入字符、删除字符等)之前,我们可以创建一个备忘录来保存当前文档的状态。如果用户执行了撤销操作,我们可以从备忘录中恢复文档的之前状态。这样就可以在不破坏TextDocument类内部结构的情况下,实现撤销功能。
五、备忘录模式的现实生活的例子
考虑拍照的过程。相机可以看作是原发器,照片就是备忘录。当我们按下快门(相当于创建备忘录)时,相机的当前状态(镜头聚焦、光圈大小、曝光设置等)被记录在照片上。我们可以将照片存储起来(相当于负责人保存备忘录),之后如果想要回顾某个瞬间(相当于恢复到之前的状态),我们可以查看对应的照片。
六、初衷与问题解决
初衷是在保持对象封装性的同时,实现对象状态的保存和恢复。通过将对象状态的保存和恢复逻辑封装在备忘录模式中,避免了外部对象直接操作对象的内部状态,从而提高了代码的可维护性和安全性。
七、代码示例 (一)Java // 备忘录类 class Memento { private String state; public Memento(String state) { this.state = state; } public String getState() { return state; } } // 原发器类 class Originator { private String state; public void setState(String state) { this.state = state; } public Memento saveToMemento() { return new Memento(state); } public void restoreFromMemento(Memento memento) { state = memento.getState(); } } // 负责人类 class Caretaker { private Memento memento; public void saveMemento(Memento memento) { this.memento = memento; } public Memento getMemento() { return memento; } } public class Main { public static void main(String[] args) { Originator originator = new Originator(); originator.setState("State 1"); Caretaker caretaker = new Caretaker(); caretaker.saveMemento(originator.saveToMemento()); originator.setState("State 2"); originator.restoreFromMemento(caretaker.getMemento()); System.out.println(originator.state); } }
类图:
流程图:
时序图:
(二)C++ #include <iostream> #include <string> // 备忘录类 class Memento { private: std::string state; public: Memento(std::string state) : state(state) {} std::string getState() const { return state; } }; // 原发器类 class Originator { private: std::string state; public: void setState(std::string state) { this->state = state; } Memento saveToMemento() { return Memento(state); } void restoreFromMemento(const Memento& memento) { state = memento.getState(); } }; // 负责人类 class Caretaker { private: Memento memento; public: void saveMemento(const Memento& memento) { this->memento = memento; } Memento getMemento() const { return memento; } }; int main() { Originator originator; originator.setState("State 1"); Caretaker caretaker; caretaker.saveMemento(originator.saveToMemento()); originator.setState("State 2"); originator.restoreFromMemento(caretaker.getMemento()); std::cout << originator.state << std::endl; return 0; }
(三)Python # 备忘录类 class Memento: def __init__(self, state): self.state = state def get_state(self): return self.state # 原发器类 class Originator: def __init__(self): self.state = None def set_state(self, state): self.state = state def save_to_memento(self): return Memento(self.state) def restore_from_memento(self, memento): self.state = memento.get_state() # 负责人类 class Caretaker: def __init__(self): self.memento = None def save_memento(self, memento): self.memento = memento def get_memento(self): return self.memento if __name__ == "__main__": originator = Originator() originator.set_state("State 1") caretaker = Caretaker() caretaker.save_memento(originator.save_to_memento()) originator.set_state("State 2") originator.restore_from_memento(caretaker.get_memento()) print(originator.state)
(四)Go package main import "fmt" // 备忘录结构体 type Memento struct { state string } func NewMemento(state string) *Memento { return &Memento{state: state} } func (m *Memento) getState() string { return m.state } // 原发器结构体 type Originator struct { state string } func (o *Originator) setState(state string) { o.state = state } func (o *Originator) saveToMemento() *Memento { return NewMemento(o.state) } func (o *Originator) restoreFromMemento(m *Memento) { o.state = m.getState() } // 负责人结构体 type Caretaker struct { memento *Memento } func (c *Caretaker) saveMemento(m *Memento) { c.memento = m } func (c *Caretaker) getMemento() *Memento { return c.memento } func main() { originator := Originator{} originator.setState("State 1") caretaker := Caretaker{} caretaker.saveMemento(originator.saveToMemento()) originator.setState("State 2") originator.restoreFromMemento(caretaker.getMemento()) fmt.Println(originator.state) }
八、备忘录模式的优缺点 (一)优点
保持封装性:原发器的内部状态对外部是隐藏的,只有原发器自身能够访问备忘录中的状态,从而保护了对象的封装性。
简化撤销/恢复操作:通过备忘录模式,撤销和恢复操作可以很容易地实现,不需要在原发器中编写复杂的状态管理代码。
提供状态历史记录:可以方便地保存多个备忘录,从而形成对象状态的历史记录,这对于需要查看对象状态变化历史的应用场景非常有用。
(二)缺点资源消耗:如果需要保存大量的备忘录,可能会消耗较多的内存资源,尤其是当备忘录对象包含大量数据时。
管理复杂度:随着备忘录数量的增加,备忘录的管理(如存储、查找、删除等)可能会变得复杂。
特性描述优点保持封装性原发器的内部状态对外部是隐藏的,只有原发器自身能够访问备忘录中的状态,从而保护了对象的封装性。简化撤销/恢复操作通过备忘录模式,撤销和恢复操作可以很容易地实现,不需要在原发器中编写复杂的状态管理代码。提供状态历史记录可以方便地保存多个备忘录,从而形成对象状态的历史记录,这对于需要查看对象状态变化历史的应用场景非常有用。缺点资源消耗如果需要保存大量的备忘录,可能会消耗较多的内存资源,尤其是当备忘录对象包含大量数据时。管理复杂度随着备忘录数量的增加,备忘录的管理(如存储、查找、删除等)可能会变得复杂。 九、备忘录模式的升级版一种常见的升级版是增加一个历史列表(History List)管理类,它可以管理多个备忘录对象,并且提供更方便的操作,如按照时间顺序查看备忘录、限制备忘录的数量以避免资源过度消耗等。例如,在文本编辑器的撤销/重做功能中,这个历史列表可以存储多个编辑操作的备忘录,并且可以方便地根据用户的操作(如多次撤销或重做)找到对应的备忘录进行状态恢复。
【再谈设计模式】备忘录模式~对象状态的守护者由讯客互联手机栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“【再谈设计模式】备忘录模式~对象状态的守护者”