天天看点

[设计模式笔记]三. 行为型模式--20. Memento模式(备忘录)对象行为型模式(一)一. 意图二. 适用性三. 模式结构四. 角色说明五. 说明六. 我的理解七. 相关模式

行为型模式--Memento模式(备忘录)对象行为型模式

一. 意图

        在不破坏封装性的前提下, 捕获一个对象的内部状态, 并在该对象之外保存这个状态. 这样以后就可将该对象恢复到原先保存的状态. 

        一个备忘录(memento)是一个对象, 它存储另一个对象在某个瞬间的内部状态, 而后者称为备忘录的原发器(originator). 当需要设置原发器的检查点时, 取消操作机制会向原发器请求一个备忘录. 原发器用描述当前状态的信息初始化该备忘录. 只有原发器可以向备忘录中存取信息, 备忘录对其他的对象"不可见".

二. 适用性

        必须保存一个对象在某一个时刻的(部分)状态, 这样以后需要时它才能恢复到先前的状态.

        如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性.

        (当我看到说需要备份一个对象的内部状态时, 我第一时间就想到, 在对象中公开一个接口用于备份对象的状态. 其实这样做是正确的, 但是不能让所有对象都能使用这个接口来获取该对象的状态, 而是使用指定类型的对象, 在该模式中该对象就是Memento类的对象.看 Originator::SetMemento(Memento m))

三. 模式结构

[设计模式笔记]三. 行为型模式--20. Memento模式(备忘录)对象行为型模式(一)一. 意图二. 适用性三. 模式结构四. 角色说明五. 说明六. 我的理解七. 相关模式

图1 

四. 角色说明

Memento(备忘录)

—备忘录存储原发器对象的内部状态. 原发器根据需要决定备忘录存储原发器的哪些内部状态.

—防止原发器以外的其他对象访问备忘录. 备忘录实际上有两个接口, 管理者(caretaker)只能看到备忘录的窄接口—它只能将备忘录传递给其他对象. 相反, 原发器能够看到一个宽接口, 允许它访问返回到先前状态所需的所有数据. 理想的情况是只允许生成本备忘录的那个原发器访问本备忘录的内部状态.

Originator(原发器)

—原发器创建一个备忘录, 以记录当前时刻它的内部状态.

—使用备忘录恢复内部状态.

Caretaker(负责人)

—负责保存好备忘录.

—不能对备忘录的内容进行操作或检查

交互

[设计模式笔记]三. 行为型模式--20. Memento模式(备忘录)对象行为型模式(一)一. 意图二. 适用性三. 模式结构四. 角色说明五. 说明六. 我的理解七. 相关模式

图2

五. 说明

1. 保持封装边界 使用备忘录可以避免暴露一些只应由原发器管理却又必须存储在原发器之外的信息. 该模式把可能很复杂的Originator内部信息对其他对象屏蔽起来, 从而保持了封装边界.

2. 它简化了原发器. 如果不使用备忘录模式, 原发器状态的备份可能需要它自己来存储.

3. 使用备忘录可能代价很高, 特别是在原发器的状态信息很复杂时, 频繁的状态拷贝, 开销会很大.

4. 维护备忘录的潜在代价, 管理器负责删除它所维护的备忘录. 然而, 管理器不知道备忘录中有多少个状态. (个人认为既然备忘录比较熟悉这些状态, 备忘录来负责对状态的删除, 而不是管理器.)

六. 我的理解

1. 备忘录模式提供了一个很好的方法: 怎样实现一个对象中的属性只对某些对象开放(通过Originator::SetMemento(Memento m)).

2. 看备忘录模式的结构图知道, Originator::SetMemento(Memento m)很关键, Originator不管理Memento, Memento由Caretaker管理.

3. 当我看到备忘录模式时, 对比它也是存储一个对象的某时刻的状态时, 我想到了Command模式. 因为Command模式实现的功能通常有向前/向后功能(例如菜单操作). 而备忘录则可以对该功能的状态存储提供实现方法.

4. 个人认为, 实现向前/向后功能更关键的是你对状态的分析, 特别是那些影响全局状态的.

七. 相关模式

Command: 命令可使用备忘录来为可撤消的操作维护状态.

Iterator: 如前所述备忘录可用于迭代.

继续阅读