备忘录模式
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。
介绍
意图: 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
主要解决: 所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
何时使用: 很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃。
如何解决: 通过一个备忘录类专门存储对象状态。
关键代码: 客户不与备忘录类耦合,与备忘录管理类耦合。
应用实例:
- 打游戏时的存档。
- Windows 里的 ctrl + z。
- 浏览器中的后退。
- 数据库的事务管理。
优点:
- 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。
- 实现了信息的封装,使得用户不需要关心状态的保存细节。
缺点:
消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。
使用场景:
- 需要保存/恢复数据的相关状态场景。
- 提供一个可回滚的操作。
注意事项:
- 为了符合迪米特原则,还要增加一个管理备忘录的类。
- 为了节约内存,可使用原型模式+备忘录模式。
代码实现
定义源发器(Originator),notePad
/*** 源发器(Originator)*/
public class NotePad {private final StringBuilder content;private final Stack<Integer> operationStack;public NotePad(){content = new StringBuilder();this.operationStack = new Stack<>();}public NotePad(String content){this();this.content.append(content);}public void write(String content){operationStack.push(this.content.length());this.content.append(content);}public void undo(){if(operationStack.isEmpty()){System.out.println("undo empty!");return;}int operation = operationStack.pop();int len = this.content.length();this.content.delete(operation,len);}public void toSnap(NotePadSnapshot notePadSnapshot){operationStack.clear();this.content.delete(0,this.content.length());this.content.append(notePadSnapshot.getSnapshot());}public NotePadSnapshot createMemento(){return new NotePadSnapshot(this.content.toString());}public void show(){System.out.println("notePad:"+this.content);}}
定义备忘录类(快照类)
public class NotePadSnapshot {private final String snapshot;public NotePadSnapshot(String snapshot){this.snapshot = snapshot;}public String getSnapshot(){return snapshot;}public void show(){System.out.println("snapshot:"+snapshot);}
}
定义快照的管理类
public class SnapshotManager {private final Map<Integer,NotePadSnapshot> snapshots = new HashMap<>();private final AtomicInteger version = new AtomicInteger(0);public void add(NotePadSnapshot notePadSnapshot){snapshots.put(version.getAndIncrement(),notePadSnapshot);}public NotePadSnapshot get(int version){return snapshots.get(version);}
}
客户端
public class Client {public static void main(String[] args) {NotePad notePad = new NotePad();notePad.write("hello world");notePad.show();notePad.write("i am a boy");notePad.show();notePad.undo();notePad.show();notePad.write("i am a girl");notePad.show();NotePadSnapshot notePadSnapshot = notePad.createMemento();notePadSnapshot.show();SnapshotManager snapshotManager = new SnapshotManager();snapshotManager.add(notePadSnapshot);notePad.write("i am a man");notePad.show();notePad.toSnap(snapshotManager.get(0));notePad.show();}
}