备忘录模式
备忘录模式能记录一个对象,当用户后悔时能撤销当前的操作,使数据恢复到它上一步的状态,在生活中有很多常见例子,如文本编辑器,游戏的存档。
假设我们要实现一个编辑器,那应该怎样实现这个功能呢? 比较好的一个方式就是:程序在执行操作时先获得编辑器对象的状态快照并保存,后可以通过快照将对象恢复到之前的状态。
那我们应该怎么创建这些状态快照呢?最粗暴的方法就是,遍历对象的所有变量并复制保存,但从外部访问要求对象的内容没有访问权限限制,这样就破坏了对象的封闭性。 并且,当对象内部增加成员时, 代码变得难以维护。
备忘录的最佳实践,是既然我们没有办法从外部获取对象的快照,那我们可以直接将生成快照的义务交给本对象(原发器Originator
),其他对象也不需要关系本对象的内部细节。
生成的快照我们将它放到另外一个类Memento
,这个类负责存储过去生成的快照,并在需要时能获取过去的快照版本。
值得注意的是,Memento并没有权限访问快照中的数据,其他对象必须通过接口访问备忘录中的数据。
同时, 原发器拥有对备忘录所有成员的访问权限, 从而能随时恢复其以前的状态。
- 原发器 (Originator) 类可以生成自身状态的快照, 也可以在需要时通过快照恢复自身状态。
- 备忘录 (Memento) 是原发器状态快照的值对象 (value object)。 通常做法是将备忘录设为不可变的, 并通过构造函数一次性传递数据。
- 负责人 (Caretaker) 仅知道 “何时” 和 “为何” 捕捉原发器的状态, 以及何时恢复状态。
Java实现
步骤:
1. 创建文本编辑器,它具有生成自己快照的功能 ,快照包括了它自身的成员变量和数据(两个类,编辑器类和快照类)
2. 将生成的快照保存到备忘录类(负责人) ,负责人只负责存储和取出状态。
3. 当编译器想要撤回时,只需要从备忘录中获得那一版本的快照,再获取快照中的数据。
编辑器类:(原发器)
class editor {
private String content ; /**user content*/
public void edit(String content ) {
this.content=content ;
}
public snapShot createSnapShot(){
return new snapShot(this.content) ;
}
public void restore(snapShot snapshot) {
content = snapshot.getContent() ;
}
public void print() {
System.out.println("现在的内容是:" + content) ;
}
}
快照类 (备忘录)
public class snapShot {
private final String content ;
snapShot(String content) {
this.content=content;
}
public String getContent(){
return content ;
}
}
备忘录类: (负责人CareTaker)
import java.util.ArrayList;
import java.util.List;
public class memento {
private List<snapShot> memento = new ArrayList<>() ;
public void push(snapShot snapshot) {
memento.add(snapshot) ;
}
public snapShot pop(){
int lastIndex = memento.size()-1 ;
snapShot lastSnapShot =memento.get(lastIndex) ;
memento.remove(lastSnapShot);
return lastSnapShot;
}
}
测试:
public class Main {
public static void main(String args[]){
editor e =new editor() ;
memento historyMemento = new memento() ;
e.edit("Hello world"); /**编辑内容 */
snapShot snapShot = e.createSnapShot(); /**创建快照 */
historyMemento.push(snapShot); /**将快照保存到备忘录里*/
e.print() ;
e.edit("哎呀写错啦") ;
historyMemento.push(e.createSnapShot());
e.print() ;
e.edit("撤回撤回");
historyMemento.push(e.createSnapShot()) ;
e.print() ;
e.restore(historyMemento.pop()); /**恢复到上一个内容 */
e.print() ;
e.restore(historyMemento.pop()); /**恢复到上一个内容 */
e.print() ;
}
}
参考文章: Click here