备忘录模式(Memento Pattern)
备忘录模式(Memento Pattern)是一种行为设计模式,它允许在不破坏封装性的前提下保存和恢复对象的内部状态。该模式涉及三个主要角色:Originator(发起人)、Memento(备忘录)和Caretaker(负责人)。Originator 是拥有内部状态的对象,Memento 是 Originator 的快照,Caretaker 负责备份和恢复 Memento。
备忘录模式在实现撤销操作和历史记录等功能时非常有用。
下面是一个使用 Go 语言实现备忘录模式的示例。在本例中,我们将实现一个简单的文本编辑器,该编辑器允许用户撤销和重做操作。
首先,我们定义 Originator 接口,该接口定义了保存当前状态和从备忘录中恢复状态的方法:
type Originator interface {
Save() Memento
Restore(m Memento)
}
接下来,我们定义 Memento 接口,该接口定义了获取备忘录的方法:
type Memento interface {
GetState() string
}
然后,我们定义 TextEditor 结构体,该结构体实现了 Originator 接口。TextEditor 结构体包含了一个字符串类型的 state 变量,它代表当前文本编辑器的状态:
type TextEditor struct {
state string
}
func (t *TextEditor) Save() Memento {
return &textMemento{state: t.state}
}
func (t *TextEditor) Restore(m Memento) {
t.state = m.GetState()
}
func (t *TextEditor) SetState(state string) {
t.state = state
}
func (t *TextEditor) GetState() string {
return t.state
}
在 TextEditor 结构体中,Save 方法将当前的 state 变量封装在textMemento 结构体中并返回,而 Restore 方法将 state 变量恢复为 Memento 中存储的状态。此外,我们还定义了 SetState 和 GetState 方法,以便在其他地方获取和设置文本编辑器的状态。
下面是textMemento结构体的定义,该结构体实现了 Memento 接口,它保存了文本编辑器的状态:
type textMemento struct {
state string
}
func (t *textMemento) GetState() string {
return t.state
}
最后,我们定义 Caretaker 结构体,该结构体负责管理 Memento。Caretaker 结构体包含了一个 mementos 切片,它用于保存 Memento。Caretaker 结构体还包含了一个 currentIndex 变量,它代表当前状态的索引:
type Caretaker struct {
mementos []Memento
currentIndex int
}
func (c *Caretaker) AddMemento(m Memento) {
c.mementos = append(c.mementos, m)
c.currentIndex = len(c.mementos) - 1
}
Caretaker 结构体的 Undo 方法用于撤销操作。它从 mementos 切片中获取上一个状态的 Memento,然后将文本编辑器的状态恢复为该 Memento 中存储的状态。该方法还将 currentIndex 变量减 1,以便在下一次 Undo 操作时返回正确的 Memento:
func (c *Caretaker) Undo(t *TextEditor) {
if c.currentIndex > 0 {
c.currentIndex--
m := c.mementos[c.currentIndex]
t.Restore(m)
}
}
Caretaker 结构体的 Redo 方法用于重做操作。它从 mementos 切片中获取下一个状态的 Memento,然后将文本编辑器的状态恢复为该 Memento 中存储的状态。该方法还将 currentIndex 变量加 1,以便在下一次 Redo 操作时返回正确的 Memento:
func (c *Caretaker) Redo(t *TextEditor) {
if c.currentIndex < len(c.mementos)-1 {
c.currentIndex++
m := c.mementos[c.currentIndex]
t.Restore(m)
}
}
最后,我们创建一个 TextEditor 实例和一个 Caretaker 实例,并测试我们的实现:
func main() {
editor := &TextEditor{}
caretaker := &Caretaker{}
editor.SetState("State #1")
caretaker.AddMemento(editor.Save())
editor.SetState("State #2")
caretaker.AddMemento(editor.Save())
editor.SetState("State #3")
caretaker.AddMemento(editor.Save())
caretaker.Undo(editor)
fmt.Println(editor.GetState())
caretaker.Redo(editor)
fmt.Println(editor.GetState())
}
在这个测试代码中,我们先设置文本编辑器的状态为 「State #1」,然后保存该状态的 Memento 并将其添加到 Caretaker 中。接着,我们将文本编辑器的状态设置为 「State #2」 并保存Memento,再将状态设置为「State #2」并保存 Memento。
接下来,我们调用 Caretaker 的 Undo 方法撤销一个操作,然后打印当前的文本编辑器状态。我们再调用 Caretaker 的 Redo 方法重做上一个操作,然后再次打印当前的文本编辑器状态。输出结果如下:
State #2
State #3
可以看到,我们成功地使用备忘录模式实现了文本编辑器的撤销和重做操作。
推荐文章: