在idea写代码的过程中,会经常用到一个快捷键——“crtl + z”,即撤销功能。“备忘录模式”则为撤销功能提供了一个设计方案。
备忘录模式提供一种状态恢复机制。在不破坏封装的前提下,捕获对象内部状态并在该对象之外保存这个状态。可以在以后将对象恢复到原先保存的状态。
图 备忘录UML
Originator:原发器,一个需要保存内部状态的普通类,可以创建一个备忘录,也可通过备忘录来恢复其在某个时候的状态。
Memento:备忘录,存储原发器的内部状态。除了原发器本身及管理者类外,备忘录不能直接供其他类使用。
CareTaker:管理者,负责保存备忘录,但不能对备忘录内容进行操作或检查,无须知道备忘录的细节。
@Data
public class IdeaCodeOriginator {
private String code;
private Integer position;
public IdeaCodeOriginator(String code, Integer position) {
this.code = code;
this.position = position;
}
public void restoreMemento(IdeaCodeMemento memento) {
this.code = memento.getCode();
this.position = memento.getPosition();
}
public IdeaCodeMemento createMemento() {
return new IdeaCodeMemento(code,position);
}
}
@Data
public class IdeaCodeMemento {
private String code;
private Integer position;
public IdeaCodeMemento(String code, Integer position) {
this.code = code;
this.position = position;
}
}
public class CareTaker {
private final Stack mementoStack = new Stack<>();
public IdeaCodeMemento getMemento(int num) {
IdeaCodeMemento memento = null;
while (num-- > 0 && !mementoStack.isEmpty()) {
memento = mementoStack.pop();
}
return mementoStack.isEmpty() ? memento : mementoStack.pop();
}
public void saveMemento(IdeaCodeMemento memento) {
mementoStack.push(memento);
}
}
public class IdeaCodeEditor {
public static void main(String[] args) {
CareTaker careTaker = new CareTaker();
IdeaCodeOriginator originator1 = new IdeaCodeOriginator("hello", 1);
careTaker.saveMemento(originator1.createMemento());
IdeaCodeOriginator originator2 = new IdeaCodeOriginator("word", 2);
careTaker.saveMemento(originator2.createMemento());
IdeaCodeOriginator originator3 = new IdeaCodeOriginator("and", 3);
careTaker.saveMemento(originator3.createMemento());
IdeaCodeOriginator originator4 = new IdeaCodeOriginator("java", 4);
careTaker.saveMemento(originator4.createMemento());
//撤回到2步前
originator4.restoreMemento(careTaker.getMemento(2));
System.out.println(originator4); // IdeaCodeOriginator(code=word, position=2)
}
}
1)要避免其他类操作或者检查备忘录的内容。
2)备忘录管理者应该具有通用性。
public interface Memento {
}
@Data
public class IdeaCodeOriginator {
private String code;
private Integer position;
public IdeaCodeOriginator(String code, Integer position) {
this.code = code;
this.position = position;
}
@Data
private static class InnerMemento implements Memento {
private String code;
private Integer position;
public InnerMemento(String code, Integer position) {
this.code = code;
this.position = position;
}
}
public Memento createMemento() {
return new InnerMemento(code,position);
}
public void restoreMemento(Memento memento) throws Exception {
if (memento instanceof InnerMemento) {
InnerMemento innerMemento = (InnerMemento) memento;
this.code = innerMemento.getCode();
this.position = innerMemento.position;
} else {
throw new Exception("类型错误");
}
}
}
public class CareTaker {
Stack stack = new Stack<>();
public T getMemento(int num) {
T memento = null;
while (num-- > 0 && !stack.isEmpty()) {
memento = stack.pop();
}
return stack.isEmpty() ? memento : stack.pop();
}
public void saveMemento(T memento) {
stack.push(memento);
}
}
public class IdeaCodeEditor2 {
public static void main(String[] args) throws Exception {
CareTaker objectCareTaker = new CareTaker<>();
IdeaCodeOriginator originator1 = new IdeaCodeOriginator("hello", 1);
objectCareTaker.saveMemento(originator1.createMemento());
IdeaCodeOriginator originator2 = new IdeaCodeOriginator("word", 2);
objectCareTaker.saveMemento(originator2.createMemento());
IdeaCodeOriginator originator3 = new IdeaCodeOriginator("and", 3);
objectCareTaker.saveMemento(originator3.createMemento());
IdeaCodeOriginator originator4 = new IdeaCodeOriginator("java", 4);
objectCareTaker.saveMemento(originator4.createMemento());
originator4.restoreMemento(objectCareTaker.getMemento(3)); // IdeaCodeOriginator(code=hello, position=1)
System.out.println(originator4);
}
}
如果需要为软件提供撤销功能,备忘录模式无疑是一种很好的解决方案。
优点:1)它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤;
缺点:1)资源消耗过大。如果要保存的原发器类的成员变量太多,就不可避免地占用大量的储存空间。每保存一次对象状态都需要消耗一定的系统资源。
1)保存一个对象在某时刻的全部或部分状态,实现撤销操作。
2)防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态实现细节暴露给外界对象。