备忘录模式(Memento Pattern,标记模式 Token Pattern,对象行为型模式)

意图

存储状态,备忘录模式用于存储状态,在java中可以使用序列化。
在不破坏封装的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。

适用性

在以下情况使用备忘录模式:
1. 必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
2. 如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏了对象的封装性。

结构

这里写图片描述

参与者

Memento

  1. 备忘录存储原发器对象的内部状态。原发器根据需要决定备忘录存储原发器的哪些内部状态。
  2. 防止原发器以外的其他对象访问备忘录。备忘录实际上有两个接口,管理者只能看到备忘录的窄接口,它只能将备忘录传递给其他对象。相反,原发器能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。理想的情况是只允许生产备忘录的原发器访问备忘录的内部状态。

Originator

  1. 原发器创建一个备忘录,用以记录当前时刻它的内部状态
  2. 使用备忘录恢复内部状态

Caretaker

  1. 负责保存好备忘录
  2. 不能对备忘录的内容进行操作或检查

代码

public interface MementoIf {

}
public class Originator {
    private int state = 0;
    private CareTaker careTaker = new CareTaker();
    public void setMemento(){
        Memento memento = (Memento) careTaker.getMemento();
        state = memento.getState();
        System.out.println("this state is "+state+" now");
    }
    public void createMemento(){
        careTaker.saveMemento(new Memento(state));
    }
    public void modifyState4Test(int m){
        state = m;
        System.out.println("this state is "+state+" now");
    }
    private class Memento implements MementoIf{
        private int state;
        private Memento(int state){
            this.state = state;
        }
        private int getState(){
            return state;
        }
    }
}
public class CareTaker {
    private MementoIf m;
    public void saveMemento(MementoIf m){
        this.m = m;
    }
    public MementoIf getMemento(){
        return m;
    }
}
public class Main {
    public static void main(String[] args) {
        Originator o = new Originator();
        o.createMemento();
        o.modifyState4Test(80);
        o.setMemento();
    }
}

协作

  1. 管理器向原发器请求一个备忘录,保留一段时间后,将其送回给原发器。有时管理者不会将备忘录返回给原发器,因为原发器可能根本不需要退到先前的状态。
  2. 备忘录是被动的。只有创建备忘录的原发器会对它的状态进行赋值和检索。

效果

保持封装边界

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

简化了原发器

在其他的保持封装性的设计中,Originator负责保持客户请求过的内部状态版本。这就把所有存储管理的重任交给了Originator。让客户管理它们请求的状态将会简化Originator,并且使得客户工作结束时无需通知原发器。

使用备忘录可能代价很高

如果原发器在生成备忘录时必须拷贝并存储大量的信息,或者客户非常频繁地创建备忘录和恢复原发器状态,可能会导致非常大的开销。除非封装和恢复Originator状态的开销不大,否则该模式可能并不是合适。

定义窄接口和宽接口

在一些语言中可能难以保证只有原发器可访问备忘录的状态。(内部类)

维护备忘录的潜在代价

管理器复杂删除它维护的备忘录。然而,管理器不知道备忘录中有多少状态。因此当存储备忘录时,一个本来很小的管理器,可能会产生大量的存储开销。

优点

  1. 将被存储的状态放在外面,不要和关键对象混在一起,可以帮助维护内聚
  2. 保持关键对象的数据封装
  3. 提供了容易实现的恢复能力

缺点

储存和恢复状态的过程可能相当耗时

实现

语言支持

备忘录有两个接口:一个为原发器所使用的宽接口,一个为其他对象所使用的窄接口。理想的实现语言应可支持两级的静态保护。在C++中,可将Originator作为Memento的一个友元,并使Memento宽接口为私有的。只有窄接口应该被声明为公共的。

存储增量式改变

如果备忘录的创建及其返回(给它们的原发器)的顺序是可预测的,备忘录可以仅存储原发器内部状态的增量改变。
例如,一个包含可撤销的命令的历史列表可使用备忘录以保证当命令被取消时,它们可以被恢复到正确的状态。历史列表定义了一个特定的顺序,按照这个顺序命令可以被取消和重做。这意味着备忘录可以只存储一个命令所产生的增量改变而不是它所影响的每一个对象的完整状态。

经典例子

游戏存档,Java序列化

相关模式

Command Pattern

若利用命令模式处理命令时,可以使用备忘录模式进行复原(undo)和重复(redo)

Prototype Pattern

备忘录模式含存储目前的对象实例状态,以便进行快照或则恢复,只会存储需要还原的信息;原型模式则是另外产生一个目前对象实例同样状态的对象实例,完全复制对象实例的内容。

State Pattern

在备忘录模式中,以对象实例表示状态,而在状态模式中以类表示状态

Iterator Pattern

备忘录模式中可使用Iterator Pattern

敬请期待“观察者模式(Observer Pattern,对象行为型模式,发布-订阅模式 Publish/Subscribe Pattern)”

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值