定义
在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
备忘录模式的定义通俗易懂,下面会通过一个例子来解释备忘录模式的应用。
实现
定义一个具有记录绘图路径的备忘录类:
public class PathMemento {
private HashMap backup;
public PathMemento(HashMap backup) {
this.backup = backup;
}
public void setBackup(HashMap backup) {
this.backup = backup;
}
public HashMap getBackup() {
return backup;
}
}
声明一个工具类,处理对象的状态备份与恢复:
public final class Beans {
public static HashMap backupBean(Object bean) {
HashMap backup = new HashMap<>();
try {
BeanInfo info = Introspector.getBeanInfo(bean.getClass());
PropertyDescriptor[] desc = info.getPropertyDescriptors();
for (int i = 0; i < desc.length; i++) {
String name = desc[i].getName();
Method getter = desc[i].getReadMethod();
Object value = getter.invoke(bean, null);
if (!name.equals("class")) {
backup.put(name, value);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return backup;
}
public static void restoreBean(Object bean, HashMap props) {
try {
BeanInfo info = Introspector.getBeanInfo(bean.getClass());
PropertyDescriptor[] desc = info.getPropertyDescriptors();
for (int i = 0; i < desc.length; i++) {
String name = desc[i].getName();
Method setter = desc[i].getWriteMethod();
if (props.containsKey(name)) {
setter.invoke(bean, props.get(name));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Path 类:
public class Path {
private int startX;
private int startY;
private int endX;
private int endY;
public PathMemento createMemento() {
return new PathMemento(Beans.backupBean(this));
}
public void restoreMemento(PathMemento memento) {
Beans.restoreBean(this, memento.getBackup());
}
@Override
public String toString() {
return "Path{" +
"startX=" + startX +
", startY=" + startY +
", endX=" + endX +
", endY=" + endY +
'}';
}
public int getStartX() {
return startX;
}
public void setStartX(int startX) {
this.startX = startX;
}
public int getStartY() {
return startY;
}
public void setStartY(int startY) {
this.startY = startY;
}
public int getEndX() {
return endX;
}
public void setEndX(int endX) {
this.endX = endX;
}
public int getEndY() {
return endY;
}
public void setEndY(int endY) {
this.endY = endY;
}
}
备忘录存储类,用于存储备忘录对象:
public class MementoBottle {
private HashMap mementos = new HashMap<>();
public void putMemento(String key, PathMemento memento) {
mementos.put(key, memento);
}
public PathMemento getMemento(String key) {
return mementos.get(key);
}
}
客户端示例:
public class Client {
public static void main(String[] args) {
Path p = new Path();
p.setStartX(0);
p.setStartY(0);
p.setEndX(16);
p.setEndY(22);
System.out.println(p);
MementoBottle bottle = new MementoBottle();
bottle.putMemento("m1", p.createMemento());
p.setStartX(3);
p.setStartY(2);
bottle.putMemento("m2", p.createMemento());
p.restoreMemento(bottle.getMemento("m1"));
System.out.println(p);
p.restoreMemento(bottle.getMemento("m2"));
System.out.println(p);
}
}
可以看出,当使用 Path 类进行路径绘制的时候,为了存储当前的路径信息,使用备忘录模式便可以达到目的。
备忘录模式相对来说比较简单,其主要实现的是对对象当前的信息进行备份,并在合适的时机恢复它。
总结
优点 实现了细节的封装,提供了“备份-恢复”模式,使得用户能够轻易地将需要备份和恢复的信息处理得得心应手。
缺点 如果需要备份的对象占用过多的内存,则每一次备份都会浪费系统资源,消耗更多内存。
Android 中的备忘录模式
public class Activity {
protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
if (mAutoFillResetNeeded) {
outState.putBoolean(AUTOFILL_RESET_NEEDED, true);
getAutofillManager().onSaveInstanceState(outState);
}
getApplication().dispatchActivitySaveInstanceState(this, outState);
}
}
扩展
除了使用 Beans 工具类进行对象的备份,还可以使用以下两种方式处理: 属性直接赋值 这种方法适合对象中属性较少、内部实现简单的场景:
public class Order {
public int state;
public Memento createMemento() {
return new Memento(state);
}
public void restore(Memento memento) {
state = memento.getState();
}
}
实现 Cloneable 接口 通过实现该接口,并重写 Object 的 clone() 方法,完成对象的拷贝:
public class Order implements Cloneable {
public int state;
public Order createMemento() {
return clone();
}
public void restore(Order memento) {
state = memento.getState();
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
@Override
protected Order clone() {
try {
return (Order) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
本文由知我者乎 原创,未经许可,不得转载!