定义
备忘录模式(Memento Pattern)又叫快照模式,它指的是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态。它是一种对象行为型模式。
上面这么说可能很难理解。 喜欢玩游戏应该都知道英雄联盟里有个英雄叫艾克,它的大招是能够逆转时间,将自己的状态和位置等返回到之前的某一个时间点的状态,我猜这里设计师可能就使用了备忘录模式,哈哈。
组成部分
备忘录模式主要有以下几个组成部分:
1、发起人类(Originator):这里主要记录当前时刻的内部状态,并且负责定义哪些是属于备份范围的状态,负责创建和恢复备忘录数据。
2、备忘录类(Memento):负责存储发起人对象的内部状态,并且在需要的时候向发起人类提供需要的内部状态。
3、管理类(Caretaker):备忘录的管理类对备忘录进行管理,保存和提供备忘录。但不能对备忘录的内容进行访问与修改。
例子
备忘录模式的例子,首先声明一个发起人类,里面主要有状态变量,还有创建备忘录和恢复备忘录的方法:
public class Originator { //状态 private String state = ""; public String getState() { return state; } public void setState(String state) { this.state = state; } //创建备忘录数据方法 public Memento create(){ return new Memento(this.state); } //恢复备忘录数据方法 public void restore(Memento memento) { this.setState(memento.getState()); } } 复制代码
接着声明一个备忘录类:
public class Memento { //状态 private String state = ""; public String getState() { return state; } public void setState(String state) { this.state = state; } public Memento(String state) { this.state = state; } } 复制代码
接着声明一个备忘录的管理类:
public class Caretaker { private Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; } } 复制代码
测试方法如下:
public class MementoPatternTest { public static void main(String[] args) { Originator originator = new Originator(); originator.setState("这是"+System.currentTimeMillis()+"的状态"); System.out.println("初始状态:"+originator.getState()); Caretaker caretaker = new Caretaker(); caretaker.setMemento(originator.create()); originator.setState("这是"+System.currentTimeMillis()+"的状态"); System.out.println("过了一段时间后状态:"+originator.getState()); originator.restore(caretaker.getMemento()); System.out.println("恢复后状态:"+originator.getState()); } } 复制代码
运行结果:
上面的例子是一个简单的单状态的备忘录模式,如果是多状态的备忘录模式可以在备忘录类中增加一个Map容器来存储所有的状态,然后在管理类中同样使用一个Map容器才存储所有的备份。比如:
class Memento { private Map<String, Object> stateMap; public Memento(Map<String, Object> map){ this.stateMap = map; } public Map<String, Object> getStateMap() { return stateMap; } public void setStateMap(Map<String, Object> stateMap) { this.stateMap = stateMap; } } 复制代码
class Caretaker { private Map<String, Memento> memMap = new HashMap<String, Memento>(); public Memento getMemento(String index){ return memMap.get(index); } public void setMemento(String index, Memento memento){ this.memMap.put(index, memento); } } 复制代码
备忘录模式的优点
1、当发起人角色中的状态改变时,有可能这是个错误的改变,我们使用备忘录模式就可以把这个错误的改变还原。
2、备忘录模式对内部状态实现了封装。除了创建它的发起人类,其他对象都不能够访问这些状态信息。
3、发起人类不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。
备忘录模式的缺点
大多数时候使用备忘录模式都是多状态的,所以对资源的消耗是较大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。
应用场景
1、游戏或者某个程序的存档功能;
2、数据库的回滚操作;
3、一些常用的备份操作。
总结
备忘录模式可以适用于保存和恢复对象的状态, 前面的创建型设计模式中的原型模式也能保存一个对象在某一个时刻的状态,那么这里的备忘录模式和原型模式区别在哪里?原型模式保存的是当前对象的所有状态信息,所以恢复的时候生成的是和保存的对象完全一样的另外一个实例;
备忘录模式保存的则是关心的在恢复时需要的对象的部分状态信息。
最后本文以及之前的所有的设计模式中的例子代码,都将同步至github,需要的欢迎下载star。