通过编辑器的例子了解备忘录模式
备忘录模式
备忘录模式是一种行为设计模式,允许在不暴露对象细节的情况下保存和恢复对象之前的状态
编辑器
接下来我们用编辑器的例子感受一下备忘录模式。
Editor.java
/**
* 编辑器
*/
public class Editor {
//历史信息栈,先进后出,最大保存个数2个
private final LimitStack history = new LimitStack(2);
private String text;
private int cursorBegin;
private int cursorEnd;
/**
* 保存
*/
public void save(){
history.addLast(createSnapShot());
}
/**
* 撤销
*/
public void revoke(){
SnapShot snapShot = history.popLast();
if (snapShot != null) {
restore(snapShot);
}
}
/**
* 还原到指定版本
* @param snapShot
*/
public void restore(SnapShot snapShot){
LoggerFactory.getLogger("Editor.restore").info("{}", snapShot);
setText(snapShot.getText());
setCursorBegin(snapShot.getCursorBegin());
setCursorEnd(snapShot.getCursorEnd());
}
public SnapShot createSnapShot(){
SnapShot snapShot = new SnapShot(text, cursorBegin, cursorEnd);
LoggerFactory.getLogger("Editor.createSnapShot").info("{}",snapShot);
return snapShot;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
this.cursorBegin = text.length();
this.cursorEnd = text.length();
LoggerFactory.getLogger("Editor.setText").info("{}", text);
}
public int getCursorBegin() {
return cursorBegin;
}
public void setCursorBegin(int cursorBegin) {
this.cursorBegin = cursorBegin;
}
public int getCursorEnd() {
return cursorEnd;
}
public void setCursorEnd(int cursorEnd) {
this.cursorEnd = cursorEnd;
}
@Override
public String toString() {
return "Editor{" +
"text='" + text + '\'' +
", cursorBegin=" + cursorBegin +
", cursorEnd=" + cursorEnd +
'}';
}
/**
* 先进后出的定长栈
*/
private static class LimitStack {
private final int count;
private final SnapShot[] array;
private int index=-1;
private LimitStack(int count) {
this.count = count;
this.array = new SnapShot[count];
LoggerFactory.getLogger("LimitStack").info("可保存的历史总数{}", count);
}
/**
* 向队尾插入一个
*/
public void addLast(SnapShot snapShot){
index++;
array[index%count] = snapShot;
LoggerFactory.getLogger("LimitStack.addLast").info("{}", snapShot);
}
public SnapShot popLast(){
int i = index % count;
SnapShot snapShot = array[i];
array[i] = null;
index--;
LoggerFactory.getLogger("LimitStack.popLast").info("{}", snapShot);
return snapShot;
}
}
}
Snapshot.java
public class SnapShot {
private final String text;
private final int cursorBegin;
private final int cursorEnd;
private final LocalDateTime creatTime;
SnapShot(String text, int cursorBegin, int cursorEnd){
this.text = text;
this.cursorBegin = cursorBegin;
this.cursorEnd = cursorEnd;
creatTime = LocalDateTime.now();
}
public LocalDateTime getCreatTime() {
return creatTime;
}
public String getText() {
return text;
}
public int getCursorBegin() {
return cursorBegin;
}
public int getCursorEnd() {
return cursorEnd;
}
@Override
public String toString() {
return "SnapShot{" +
"text='" + text + '\'' +
", cursorBegin=" + cursorBegin +
", cursorEnd=" + cursorEnd +
", creatTime=" + creatTime +
'}';
}
}
MementoMain.java
public class MementoMain {
public static void main(String[] args) {
Editor editor = new Editor();
editor.setText("大家好!");
editor.save();
editor.setText(editor.getText()+"我是");
editor.save();
editor.setText(editor.getText()+"张三");
editor.save();
editor.setText(editor.getText()+",法外狂徒");
editor.revoke();
editor.revoke();
editor.revoke();
}
}
运行结果
总结
-
在备忘录模式中存在三个角色:
- 原发器(Originator):可以生成自身状态的快照,也可以在需要的时候通过快照恢复自身状态,就好像上面代码中的
Editor
一样。 - 备忘录(Memento):是原发器快照的值对象(value object)。通常做法是将备忘录设置为不可变的,并通过构造函数一次性传递数据,就好像上面代码中的
Snapshot
一样,Snapshot
中存储了Editor
实例的状态信息,并且所有的信息都是final类型的。 - 负责人(Caretaker):通过保存备忘录栈来记录原发器的历史状态。 就好像
LimitStack
一样。
- 原发器(Originator):可以生成自身状态的快照,也可以在需要的时候通过快照恢复自身状态,就好像上面代码中的
-
应用场景:
- 当你需要创建对象快照来恢复其之前的状态时,可以使用备忘录模式,比如各种类型的编辑器。
- 需要提供保存与恢复的业务场景,比如游戏中的存档和读档。