设计模式(十八)—备忘录模式

最后更新于:2022-04-01 16:26:32

 **定义**:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将 该对象恢复到原先保存的状态。 ## 一般模式: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-06_5755340c961b6.jpg) Originator发起人角色 ---|记录当前时刻的内部状态,负责定义那些属于备份范围的状态,负责创建和恢复备忘录数据 Memento备忘录角色 ---|负责存储Originator发起人对象的内部状态,在需要的时候提供发起人需要的内部状态 Caretaker备忘录管理员角色 ---|对备忘录进行管理、保存和提供备忘录。 ~~~ public class MementoTest { public static void main(String[] args) { //定义一个备忘录的发起者 Originator origin = new Originator(); origin.setState("你好!"); //定义一个备忘录的管理者 Caretaker care = new Caretaker(); //创建一个备忘录 care.setMemento(origin.createMemento()); origin.setState("去死吧!"); //恢复原有的数据 origin.restoreMemento(care.getMemento()); System.out.println(origin.getState()); } } /** * 备忘录发起人的角色, * 备忘录中保存的就是该类的内容。 * @author admin * */ class Originator{ //一个String类型表示当前状态 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 restoreMemento(Memento memento){ this.setState(memento.getState()); } } /** * 备忘录角色, * 该类用于备份、存储原有数据。 * @author admin * */ class Memento{ //一个String类型表示当前状态 private String state = ""; public Memento(String state) { this.state = state; } public String getState() { return state; } public void setState(String state) { this.state = state; } } /** * 备忘录的管理类 * 对备忘录进行管理、保存和存储 * @author admin */ class Caretaker{ private Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; } } ~~~ ## 一个例子: 模拟月光宝盒中,至尊宝阻止白晶晶自杀的桥段。当白晶晶在洞内自杀,至尊宝没有来得及救,于是就使用月光宝盒--菠萝菠萝蜜 任何就回到上一个状态,继续去救白晶晶,知道能够成功救到为止。 这个例子可以说明,救白晶晶之前,首先保存一个状态命名为1,从这一状态出发,如果没有成功,就回到1状态。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-06_5755340cb924d.jpg) ~~~ public class MementoT { public static void main(String[] args) { //创建一个发起者,(看见白晶晶在自杀) SaveLifeAction action = new SaveLifeAction(); action.setState("白晶晶被至尊宝伤透了心...准备拿剑抹脖子自杀"); //月关宝盒时刻记录每一瞬间 BoxManager boxManager = new BoxManager(); boxManager.setBoxMemento(action.createMemento()); action.setState("白晶晶自杀死了..."); System.out.println(action.getState()); System.out.println("---至尊宝拿着月关宝盒,回去救她----"); //至尊宝拿着月关宝盒,回去救她 action.restoreMemento(boxManager.getBoxMemento()); //回到上一状态 System.out.println(action.getState()); action.setSuccess(true); if(action.isSuccess()){ System.out.println("----白晶晶成功获救!"); } } } /** * 该类是发起者类, * 设置负责创建和恢复备忘录 * @author admin * */ class SaveLifeAction{ //定义一个状态,用于描述当前正在做什么.. private String state=""; //设置是否救成功 private boolean isSuccess; public String getState() { return state; } public void setState(String state) { this.state = state; } public boolean isSuccess() { return isSuccess; } public void setSuccess(boolean isSuccess) { this.isSuccess = isSuccess; } //创建一个备份的状态 public BoxMemento createMemento(){ return new BoxMemento(this.state); } //恢复到原来的状态 public void restoreMemento(BoxMemento boxMemento){ this.setState(boxMemento.getState()); } } /** * 该类是备忘录类 * 相当于故事中的月光宝盒,他带你回到上一个状态。 * 内部实现的原理就是,保存上一状态而已。 * @author admin * */ class BoxMemento{ private String state=""; public BoxMemento(String state) { this.state = state; } public String getState() { return state; } public void setState(String state) { this.state = state; } } /** * 备忘录的管理者, * 谁拿到月光宝盒,谁就可以操纵月光宝盒, * 就可以回到过去。 * @author admin * */ class BoxManager{ private BoxMemento boxMemento; public BoxMemento getBoxMemento() { return boxMemento; } public void setBoxMemento(BoxMemento boxMemento) { this.boxMemento = boxMemento; } } ~~~ **备忘录模式的使用场景** ---|需要保存和恢复数据的相关状态场景。 ---|提供一个可回滚(rollback)的操作,比如word中Ctrl+Z的组合键。 ---|需要监控的副本场景中。 ---|数据库连接的事务管理就是用的备忘录模式。 ## 备忘录的扩展 ---|1、实现java类中的Cloneable实现备忘录模式      使用clone方式的备忘录模式,可以使用在比较简单的场景或者比较单一的场景中,      尽量不要与其他的对象产生严重的耦合关系。 ~~~ public class MementoExpand { public static void main(String[] args) { //定义一个发起人 OriginClass origin = new OriginClass(); origin.setState("我的原始状态"); //创建备份 origin.createOrigin(); origin.setState("我的现在状态.."); System.out.println(origin.getState()); System.out.println("------我不喜欢现在的状态-------"); //恢复原来的状态 origin.restoreOrigin(); System.out.println(origin.getState()); } } /** * 发起者实现Cloneable接口,完成自身的备忘录设置。 * 无需接触其他类来保存自身的当前状态。 * @author admin * */ class OriginClass implements Cloneable{ private String state; //自身的备忘录角色 private OriginClass backUp; public String getState() { return state; } public void setState(String state) { this.state = state; } //创建备份 public void createOrigin(){ this.backUp = (OriginClass) this.clone(); } //恢复原来的信息 public void restoreOrigin(){ this.setState(backUp.getState()); } @Override protected Object clone() { try { return (OriginClass) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } } ~~~ ---|2多状态的备忘录模式 ~~~ /** * 通过java.beans.Introspector类获取其他类中的属性和方法 * @author admin * */ public class BeanUtil { public static void main(String[] args) { //创建一个发起者 MyOringin origin = new MyOringin("lzl",10000,"程序员"); System.out.println("在百度公司里:"+origin.toString()); //在百度公司创建备份 MyMementor mementor = origin.createMemento(); System.out.println("感觉太累了,跳槽的阿里巴巴..."); origin.setName("lzl"); origin.setPosition("程序员"); origin.setSalary(12000); System.out.println("跳槽到阿里:"+origin.toString()); System.out.println("----------------在这里更累,跟着老大,10天没合眼...想回到百度了."); origin.restoreMemento(mementor); System.out.println("回到百度,还是很轻松的。。"+origin.toString()); } //获取发起者类中的属性参数,并保存在hashMap中 public static HashMap<String, Object> backUpProp(Object bean){ HashMap<String, Object> result = new HashMap<String, Object>(); //获得Bean描述 try { BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); //返回PropertyDescriptor类型的javaBean描述 PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); //遍历返回的javaBean for(PropertyDescriptor des : descriptors){ String fieldName = des.getName(); //读取属性的方法 Method getter = des.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){ //获取BeanInfo try { BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); //获取PropertyDescriptor的对象数组 PropertyDescriptor[] descripors = beanInfo.getPropertyDescriptors(); //增强for循环,遍历所有的属性,设置到bean中 for(PropertyDescriptor des : descripors){ //获取key值对象 String fieldName = des.getName(); //如果包含这个属性 if(propMap.containsKey(fieldName)){ //获取属性set的方法 Method setter = des.getWriteMethod(); setter.invoke(bean, new Object[]{propMap.get(fieldName)}); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 类的发起者,模拟拥有多个属性。 * @author admin * */ class MyOringin{ //姓名 private String name; //薪水 private double salary; //职位 private String position; public MyOringin(String name,double salary,String position) { this.name = name; this.salary = salary; this.position = position; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public String getPosition() { return position; } public void setPosition(String position) { this.position = position; } //创建一个备份 public MyMementor createMemento(){ //将方法属性存储到BeanUtil.backUpProp()中的hashMap中 return new MyMementor(BeanUtil.backUpProp(this)); } public void restoreMemento(MyMementor memento){ BeanUtil.restoreProp(this, memento.getBeanMap()); } @Override public String toString() { return "姓名:"+this.name+"\t职位:"+this.position +"\t薪水:"+this.salary+"\t"; } } /** * 备忘录类,用于保存原有的状态。 * @author admin */ class MyMementor{ //定义一个hashMap来接收发起者的所有属性状态备份 private HashMap<String, Object> beanMap = new HashMap<String, Object>(); public MyMementor(HashMap<String, Object> beanMap) { this.beanMap = beanMap; } public HashMap<String, Object> getBeanMap() { return this.beanMap; } public void setBeanMap(HashMap<String, Object> beanMap) { this.beanMap = beanMap; } } ~~~
';