设计模式-22-备忘录模式

备忘录模式是一种行为设计模式,允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态

逻辑结构

备忘录模式涉及三个核心角色:

  • Originator(原发器): 需要被保存和恢复状态的对象。创建一个备忘录对象,用于保存当前状态,也可以通过备忘录对象恢复到之前的状态。

  • Memento(备忘录): 用于存储原发器对象状态的对象。备忘录对象可以记录原发器的内部状态,也可以提供访问原发器状态的接口。

  • Caretaker(负责人): 负责保存备忘录对象,但是不能对备忘录对象进行操作或检查其内容。它只负责将备忘录对象传递给原发器对象

Memento

代码实现

代码路径:https://github.com/XBoom/DesignPatterns/tree/main/21_Memento

  1. 首先,定义原发器结构体 Originator,该结构体具有保存和恢复状态的方法

    1
    2
    3
    4
    5
    6
    7
    8
    // Memento 备忘录对象
    type Memento struct {
    state string
    }

    func (m *Memento) GetState() string {
    return m.state
    }
  2. 然后,定义备忘录结构体 Memento,用于存储原发器的状态:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // Originator 发起者对象
    type Originator struct {
    state string
    }

    func (o *Originator) SetState(state string) {
    o.state = state
    }

    func (o *Originator) CreateMemento() *Memento {
    return &Memento{state: o.state}
    }

    func (o *Originator) RestoreMemento(m *Memento) {
    o.state = m.GetState()
    }
  3. 最后,定义负责人结构体 Caretaker,负责保存和获取备忘录对象:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // Caretaker 备忘录管理器
    type Caretaker struct {
    memento *Memento
    }

    func (c *Caretaker) GetMemento() *Memento {
    return c.memento
    }

    func (c *Caretaker) SetMemento(m *Memento) {
    c.memento = m
    }

执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//1. 原始对象设置状态
originator := &Originator{}
originator.SetState("State 1")
fmt.Println("当前状态:", originator.state)

//2. 备忘发起者
caretaker := &Caretaker{}
// 创建备忘录并保存状态
caretaker.SetMemento(originator.CreateMemento())

originator.SetState("State 2")
fmt.Println("更新后状态:", originator.state)

//3. 恢复状态
originator.RestoreMemento(caretaker.GetMemento())
fmt.Println("恢复后状态:", originator.state)

结果

1
2
3
当前状态: State 1
更新后状态: State 2
恢复后状态: State 1

为什么不直接保存原发器而要将对象中的内容保存到另外一个对象中?

答:当直接保存的时候,或多或少原发器中的内容就已经暴露出来了。而通过单独封装一个备忘录负责人,客户端是无感知的,仅仅是恢复内容

适用场景

  • 当需要保存和恢复对象的状态,并且希望在不破坏对象封装性的情况下进行操作时,可以使用备忘录模式。
  • 当需要提供撤销操作的功能,或者需要实现 “撤销-重做” 的功能时,备忘录模式可以很好地支持这种需求。
  • 当需要保存对象状态的历史记录,以便进行回溯或者比较时,备忘录模式也是一个不错的选择。

总结

  • 可以在不破坏对象封装情况的前提下创建对象状态快照
  • 可以通过让负责人维护原发器状态历史记录来简化原发器代码

参考链接

  1. https://refactoringguru.cn/design-patterns/memento
  2. https://lailin.xyz/post/memento.html