Without violating encapsulation, capture and externalize an object’s internal state so that the object can be restored to this state later.
备忘录模式的通用类图
备忘录模式的通用源码
发起让人角色
public class Originator { private String state; //备份 public Memento createMemento() { return new Memento(this.state); } //恢复 public void restoreMemento(Memento memento) { this.setState(memento.getState()); } public String getState() { return state; } public void setState(String state) { this.state = state; } }
备忘录角色
public class Memento { private String state; public Memento(String state) { this.state = state; } public String getState() { return state; } public void setState(String state) { this.state = state; } }
备忘录管理员角色
public class Caretaker { private Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; } }
场景类
public class Client { public static void main(String[] args) { Originator originator = new Originator(); Caretaker caretaker = new Caretaker(); originator.createMemento(); originator.restoreMemento(caretaker.getMemento()); } }
备忘录模式的使用场景
- 要保存和恢复数据的相关状态场景。
- 提供一个可回滚的操作。
- 需要监控的副本场景中。
- 数据库连接事务管理。
备忘录模式的注意事项
- 备忘录的生命周期。备忘录创建出来就要在“最近”的代码中使用,要主动管理他的生命周期,建立就要使用,不用就要立即删除其引用,等待垃圾回收器对其回收。
- 备忘录的性能。不要在频繁建立备份的场景中使用备忘录模式,比如for循环,因为控制不了备忘录的建立对象的数量,另外他的建立还需要消耗资源。
备忘录模式的简单应用的类图及源码
发起角色
public class Boy { private String state; public void changeState() { this.state = "心情不好"; } //备份 public Memento createMemento() { return new Memento(this.state); } //恢复 public void restoreMemento(Memento _memento) { this.setState(_memento.getState()); } public String getState() { return state; } public void setState(String state) { this.state = state; } }
备忘录角色
public class Memento { private String state; public Memento(String state) { this.state = state; } public void setState(String state) { this.state = state; } public String getState() { return state; } }
管理备忘录角色
public class Caretaker { private Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; } }
场景类
public class Client { public static void main(String[] args) { Boy boy = new Boy(); Caretaker caretaker = new Caretaker(); boy.setState("心情好"); System.out.println(boy.getState()); caretaker.setMemento(boy.createMemento()); boy.changeState(); System.out.println(boy.getState()); boy.restoreMemento(caretaker.getMemento()); System.out.println(boy.getState()); } }
备忘录模式的扩展应用
clone方式的备忘录
发起角色
public class Originator implements Cloneable { private Originator backup; private String state; public String getState() { return state; } public void setState(String state) { this.state = state; } //备份 public void createMemento() { this.backup = this.clone(); } //恢复 public void restoreMemento() { this.setState(this.backup.getState()); } @Override protected Originator clone() { try { return (Originator)super.clone(); } catch (Exception e) { e.printStackTrace(); } return null; } }
场景类
public class Client { public static void main(String[] args) { Originator originator = new Originator(); originator.setState("hao"); System.out.println(originator.getState()); originator.createMemento(); originator.setState("buhao"); System.out.println(originator.getState()); originator.restoreMemento(); System.out.println(originator.getState()); } }
注:结合原型模式和备忘录模式,需要考虑原型模式的深拷贝和浅拷贝的问题,在复杂的场景中它会让程序变得逻辑异常混乱,出现错误也很跟踪。
多状态的备忘录模式
发起角色
public class Originator { private String state1; private String state2; private String state3; public String getState1() { return state1; } public void setState1(String state1) { this.state1 = state1; } public String getState2() { return state2; } public void setState2(String state2) { this.state2 = state2; } public String getState3() { return state3; } public void setState3(String state3) { this.state3 = state3; } //备份 public Memento createMemento() { return new Memento(BeanUtils.backupProp(this)); } //恢复 public void restoreMemento(Memento memento) { BeanUtils.restoreProp(this, memento.getStateMap()); } @Override public String toString() { return "state1=" + state1 + "\nstate2=" + state2 + "\nstate3=" + state3; } }
备忘录角色
public class Memento { //接受HashMap作为状态 private HashMap<String, Object> stateMap; //接受一个对象,建立一个备份 public Memento(HashMap<String, Object> map) { this.stateMap = map; } public HashMap<String, Object> getStateMap() { return stateMap; } public void setStateMap(HashMap<String, Object> stateMap) { this.stateMap = stateMap; } }
工具类
import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.util.HashMap; public class BeanUtils { //把bean所有的属性及数值放入到HashMap中 public static HashMap<String, Object> backupProp(Object bean) { HashMap<String, Object> result = new HashMap<String, Object>(); try { //获得Bean描述 BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); //获得属性描述 PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); //遍历所有属性 for(PropertyDescriptor descriptor : descriptors) { //属性名称 String fieldName = descriptor.getName(); //读取属性的方法 Method getter = descriptor.getReadMethod(); //读取属性值 Object fieldValue = getter.invoke(bean, new Object[]{}); if(!fieldName.equalsIgnoreCase("class")) { result.put(fieldName, fieldValue); } } } catch (Exception e) { e.printStackTrace(); } return result; } //把HashMap的值返回到bean中 public static void restoreProp(Object bean, HashMap<String, Object> propMap) { try { //获得Bean描述 BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); //获得属性描述 PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); //遍历所有属性 for(PropertyDescriptor descriptor : descriptors) { //属性名称 String fieldName = descriptor.getName(); //如果有这个属性 if (propMap.containsKey(fieldName)) { //写属性的方法 Method setter = descriptor.getWriteMethod(); setter.invoke(bean, new Object[]{propMap.get(fieldName)}); } } } catch (Exception e) { System.out.println("shit"); e.printStackTrace(); } } }
场景类
public class Client { public static void main(String[] args) { Originator originator = new Originator(); originator.setState1("111"); originator.setState2("222"); originator.setState3("333"); System.out.println(originator.toString()); Memento memento = originator.createMemento(); originator.setState1("qqq"); originator.setState2("www"); originator.setState3("eee"); System.out.println(originator.toString()); originator.restoreMemento(memento); System.out.println(originator.toString()); } }
注:备份了很多属性,但是没有实现多备份的备忘录,接下来讲解多备份的备忘录模式
多备份的备忘录
在上述的示例中实现多备份,只需要增加备忘录管理员角色的源码和修改对应的场景类。
增加的备忘录管理员角色
public class Caretaker { //容纳备忘录的容器 private HashMap<String, Memento> mementoMap = new HashMap<String, Memento>(); public HashMap<String, Memento> getMementoMap() { return mementoMap; } public void setMementoMap(HashMap<String, Memento> mementoMap) { this.mementoMap = mementoMap; } }
修改的场景类
public class Client1 { public static void main(String[] args) { //定义出发人 Originator originator = new Originator(); Caretaker caretaker = new Caretaker(); //创建备忘录 caretaker.setMemento("111", originator.createMemento()); caretaker.setMemento("222", originator.createMemento()); //恢复一个指定标记的备忘录 originator.restoreMemento(caretaker.getMemento("111")); } }
封装得更好一点
在系统管理上,一个备份的数据是完全、绝对不能修改的,它保证数据的洁净,避免数据污染而使备份失去意义。备份是不能被篡改的,也就是说需要缩小备份出的备忘录的阅读权限,保证发起人可读就OK了。
发起人角色
public class Originator { private String state = ""; public String getState() { return state; } public void setState(String state) { this.state = state; } //备份 public IMemento createMemento() { return new Memento(this.state); } //恢复 public void restoreMemento(IMemento memento) { this.setState(((Memento)memento).getState()); } //内部类 private class Memento implements IMemento { //发起人的内部状态 private String state = ""; //构造函数传递参数 private Memento(String state) { this.state = state; } private String getState() { return state; } private void setState(String state) { this.state = state; } } }
备忘录接口
public interface IMemento { }
管理备份录角色
public class Caretaker { private IMemento memento; public IMemento getMemento() { return memento; } public void setMemento(IMemento memento) { this.memento = memento; } }
场景类
public class Client { public static void main(String[] args) { Originator originator = new Originator(); Caretaker caretaker = new Caretaker(); originator.setState("hello"); System.out.println(originator.getState()); originator.createMemento(); originator.setState("wellow"); System.out.println(originator.getState()); originator.restoreMemento(caretaker.getMemento()); System.out.println(originator.getState()); } }