在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<IdeaCodeMemento> 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<T> {
-
- Stack<T> 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<Memento> 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)防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态实现细节暴露给外界对象。