备忘录模式
介绍
备忘录模式(Memento Pattern)是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,且在需要时可以将该对象恢复到原先保存的状态。用户不需关心对象的内部状态或者保存和恢复的细节。
可以这里理解备忘录模式:现实生活中的备忘录是用来记录某些要去做的事情,或者是记录己经达成的共同意见的事情,以防忘记了。而在软件层面,备忘录模式有着相同的含义,备忘录对象主要用来记录一个对象的某种状态,或者某些数据,当要做回退时,可以从备忘录对象里获取原来的数据进行恢复操作
备忘录模式属于行为型模式
缺点:耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。
为了节省内存,备忘录模式可以与原型模式搭配使用
使用场景:
- 存档
- 用户撤销行为
- 数据库事务管理
原理和角色
想要备份一个对象的状态,就需要获取其属性,保存到备忘录对象中。但一般这些属性都是私有的。为了不破坏封装性,我们可以让对象自己承担构造备忘录对象的工作。
或:
- Originator:需要保存状态的对象
- Memento:备忘录对象,负责保护好记录,即Originator内部状态
- Caretaker:守护者对象(可选)负责保护一个或多个目标对象的一个或多个备忘录对象(不同时期的多个状态)。可以使用列表、Map、栈等数据结构保存。
代码示例:
public class MementoPattern {
public static void main(String[] args) {
History history = new History();
Document document = new Document();
document.setContent("11111");
history.add(document.save());
// 修改
document.setContent("22222");
// 备份的恢复
document.resume(history.getLastVersion());
System.out.println(document.getContent()); // 111111
}
}
/** 需要备份的对象 */
class Document {
private String content;
/** 备份 */
public BackUp save() {
// 传入需要备份的属性
return new BackUp(content);
}
public void resume(BackUp backUp) {
content = backUp.getContent();
}
// content的getter/setter
}
/** 备忘录对象接口 */
interface Memento {
}
/** 备忘录对象,实现接口,且其属性要与目标对象的属性相同 */
class BackUp implements Memento {
private String content;
public BackUp(String content) {
// 克隆新对象,深拷贝!可以结合原型模式
this.content = new String(content);
}
// content的getter/setter
}
/** 守护者对象Caretaker */
class History {
Stack<BackUp> history = new Stack<>();
public void add(BackUp backUp) {
history.add(backUp);
}
public BackUp getLastVersion() {
return history.pop();
}
}