备忘录模式(行为型模式)
模式概述
备忘录模式是一种行为设计模式,它允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。
问题
李星云现在正在开发一款编辑器,除了简单的文字编辑功能外,编辑器中可以嵌入图片。
一般来说,编辑器都允许用户执行撤销(undo)操作,也就是恢复到之前的编辑状态。
李星云的方案是:将所有历史数据都保存到类的成员变量中去,而且这些成员变量都被设成了公有属性,也就是public
。
但这会暴露一切编辑器的状态,也不够安全。但如果将它们全都设为私有属性,也就是private
,但这样一来,对象又没有足够的访问权限来将数据保存到成员变量中去。
方案
备忘录模式建议将对象状态的副本存储在一个名为备忘录Memento
的特殊对象中。除了创建备忘录的对象外,任何对象都不能访问备忘录的内容。
其他对象必须使用受限接口与备忘录进行交互,它们可以获取快照的元数据(创建时间和操作名称等),但不能获取快照中原始对象的状态。
通过备忘录模式,现在李星云可以将创建快照的工作委派给一个名为源发器(Originator)的对象,它是实际状态的拥有者。
通过它而不是编辑器自身来生成和访问所有的快照,也就是历史记录。
结构

实现
Java
/**
* 备忘录
*
*/
public class Memento {
private String state;
public Memento(String state) {
this.state=state;
}
public void setState(String state) {
this.state=state;
}
public String getState() {
return state;
}
}
/**
* 源发器
*
*/
public interface Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
public Memento createMemento() {
return new Memento(state);
}
public void restoreMemento(Memento m) {
this.setState(m.getState());
}
}
/**
* 管理者
*
*/
public class Caretaker {
private Memento memento;
public void setMemento(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
}
Go
package main
import "fmt"
/**
* 原发器
*
*/
type Originator struct {
state string
}
func (e *Originator) createMemento() *Memento {
return &Memento{state: e.state}
}
func (e *Originator) restoreMemento(m *Memento) {
e.state = m.getSavedState()
}
func (e *Originator) setState(state string) {
e.state = state
}
func (e *Originator) getState() string {
return e.state
}
/**
* 备忘录
*
*/
type Memento struct {
state string
}
func (m *Memento) getSavedState() string {
return m.state
}
/**
* 负责人
*
*/
type Caretaker struct {
mementoArray []*Memento
}
func (c *Caretaker) addMemento(m *Memento) {
c.mementoArray = append(c.mementoArray, m)
}
func (c *Caretaker) getMemento(index int) *Memento {
return c.mementoArray[index]
}
/**
* 客户端
*
*/
func main() {
caretaker := &Caretaker{
mementoArray: make([]*Memento, 0),
}
originator := &Originator{
state: "A",
}
fmt.Printf("原发器当前状态:%s\n", originator.getState())
caretaker.addMemento(originator.createMemento())
originator.setState("B")
fmt.Printf("原发器当前状态:%s\n", originator.getState())
caretaker.addMemento(originator.createMemento())
originator.setState("C")
fmt.Printf("原发器当前状态:%s\n", originator.getState())
caretaker.addMemento(originator.createMemento())
originator.restoreMemento(caretaker.getMemento(1))
fmt.Printf("恢复到状态:%s\n", originator.getState())
originator.restoreMemento(caretaker.getMemento(0))
fmt.Printf("恢复到状态:%s\n", originator.getState())
}
适用场景
- 当需要通过快照来恢复对象或数据之前的状态时,可以使用备忘录模式。
优缺点
备忘录模式的优点。
可以在不破坏对象封装情况的前提下创建对象的快照。
将生成快照的代码从源发器中剥离,符合
单一职责原则
。
备忘录模式的缺点。
负责人Caretaker必须完整跟踪源发器的生命周期才能销毁弃用的备忘录。
引入源发器与管理者会使代码变得更复杂。
相关性
可以同时使用
命令模式
和备忘录模式
来实现“撤销”。此时命令模式
用于对目标对象执行各种不同的操作,而备忘录模式
则用来保存一条命令执行前对象的状态。可以同时使用
备忘录模式
和迭代器模式
来获取当前迭代器的状态,并在需要的时候回滚。当不需要链接其他外部资源,存储的对象状态比较简单时,
原型模式
可以作为一个简化版本的备忘录模式
。
感谢支持
更多内容,请移步《超级个体》。