备忘录模式属于三种设计模式中的行为型模式(另外两种是建立型模式和结构型模式)。java
定义:在不破坏封闭性的前提下,捕获一个对象的内部状态,并在该对象以外保存这个状态。这样之后就能够将改变了的对象恢复到原先保存的状态。设计模式
之因此须要存储改变前的对象,是由于java对象的传递是引用传递。A a1=a,a里面的东西变就等同于a1里面的东西变。
架构
备忘录模式的结构:ide
发起人:负责记录当前时刻的内部状态,负责定义那些属于备忘范围的状态,负责建立和恢复备忘录数据。测试
备忘录:负责存储发起人对象的内部状态,在须要的时候提供发起人须要的内部状态。this
管理角色:对备忘录进行管理,保存和提供备忘录。spa
优势:设计
当发起人角色中的状态改变时,有可能这是个错误的改变,咱们使用备忘录模式就能够还原。rest
备份的状态是保存在发起人角色以外的,这样,发起人角色就不须要对哥哥备份状态进行管理。代码规范
若是有须要提供回滚操做的需求,使用备忘录模式很是合适
缺点:
在实际应用中,备忘录模式多事多状态和多备份的,发起人角色的状态须要存储到备忘录对象中,对字段的小号是比较严重的。
从设计模式角度讲:我的感受他对六大设计模式原则的体现不是很大,只能说知足单一职责原则把,好比一个类的实例若是想要从不能备忘改成须要备忘,经过该模式,咱们仍是要为该类增长一个保存和恢复的方法,违背了开闭原则,client端调用的时候须要知道。为何不直接定义一个容器,拷贝一个该对象,须要回复的时候再赋值过去呢(这样貌似又不三不四了,由于体现不出来备忘是某个对象的能力,略纠结啊)。(欢迎大神透彻分析下)
简单版测试用例:
public class BeiwangluTest { public static void main(String[] args) { Originator originator=new Originator(); originator.setState("状态1"); Caretaker caretaker=new Caretaker(); caretaker.setMemento(originator.createMemento()); originator.setState("状态2"); originator.restorMemento(caretaker.getMemento()); System.out.println(originator.getState());;//这是以前的状态 originator.createMemento();//这是以前的memento } } /** * 发起ren * @author 58 * */ class Originator{ private String state=""; public String getState() { return state; } public void setState(String state) { this.state = state; } public Memento createMemento(){ return new Memento(this.state); } public void restorMemento(Memento memento){ this.setState(memento.getState()); } } /** * 备忘录 * @author 58 * */ 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; } } /** * 管理角色 * @author 58 * */ class Caretaker{ private Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; } }
上述代码只作到恢复了一个状态,通常状况下咱们须要恢复的是一个复杂的对象。
最经常使用的方法是在memento中增长一个map容器来存储全部的状态,在caretaker类中一样适用一个map容器存储全部备份。下面代码以下(应该也能够经过深拷贝实现,经过beanutils来实现会更更简单,有时间的话试试)
(话外代码规范:写代码时名字要起好,在方法中list list=xxx这种就很差,应该表示清楚list是干吗的,否则看起来很费劲。简单命名应该只出如今循环遍历中,trycatch等代码常常会给咱们生成一个//TODO注释,这个注释不要留,会让有代码洁癖的人反感,能够从eclipese设置里去掉,要是不知道为何,本身去百度//TODO,//XXX,//FIXME 这些注释各自都是干吗用的,严格要求从我作起)
public class BeiwangluTest { public static void main(String[] args) { Originator ori=new Originator(); Caretaker caretaker=new Caretaker(); ori.setState1("中国"); ori.setState2("强盛"); ori.setState3("繁荣"); System.out.println("状态1"+ori); caretaker.setMemento("001",ori.createMemento()); ori.setState1("软件"); ori.setState2("架构"); ori.setState3("优秀"); System.out.println("状态2"+ori); ori.restorMemento(caretaker.getMemento("001")); System.out.println("回复后的状态"+ori); } } /** * 发起人 * * @author 58 * */ class Originator { private String state1 = ""; private String state2 = ""; private String state3 = ""; public Memento createMemento() { return new Memento(BeanUtils.backupProp(this)); } public void restorMemento(Memento memento) { BeanUtils.restoreProp(this, memento.getStateMap()); } 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; } @Override public String toString() { return "Originator [state1=" + state1 + ", state2=" + state2 + ", state3=" + state3 + "]"; } } /** * 备忘录 * * @author 58 * */ class Memento { private Map<String, Object> stateMap; public Memento(Map<String, Object> map) { this.stateMap = map; } public Map<String, Object> getStateMap() { return stateMap; } public void setStateMap(Map<String, Object> stateMap) { this.stateMap = stateMap; } } /** * 管理角色 * * @author 58 * */ class Caretaker { private Map<String, Memento> meMap = new HashMap<String, Memento>(); public Memento getMemento(String index) { return meMap.get(index); } public void setMemento(String index, Memento memento) { this.meMap.put(index, memento); } private Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; } } class BeanUtils { public static Map<String, Object> backupProp(Object bean) { Map<String, Object> result = new HashMap<String, Object>(); try { BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); PropertyDescriptor[] descriptors = beanInfo .getPropertyDescriptors(); for (PropertyDescriptor descriptor : descriptors) { String fieldName = descriptor.getName(); Method getter = descriptor.getReadMethod(); // TODO null和new Object[]{}是不同的,null通常是执行抽象方法。 Object fieldValue = getter.invoke(bean, new Object[]{}); if (!fieldName.equalsIgnoreCase("class")) { result.put(fieldName, fieldValue); } } } catch (IntrospectionException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return result; } public static void restoreProp(Object bean, Map<String, Object> propMap) { try { BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); PropertyDescriptor[] descriptors = beanInfo .getPropertyDescriptors(); for (PropertyDescriptor descriptor : descriptors) { String fieldName = descriptor.getName(); if (propMap.containsKey(fieldName)) { Method setterMethod = descriptor.getWriteMethod(); setterMethod.invoke(bean, new Object[] { propMap.get(fieldName) }); } } } catch (IntrospectionException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }