接上篇《设计模式之禅》--备忘录扩展:clone方式的备忘录
需求:对象全状态备份方案
发起人
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()); } //增加一个toString方法 @Override public String toString() { return "state1=" + state1 + " stat2=" + state2 + " state3=" + state3; } }
BeanUtils工具类
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 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) { //异常处理 } 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 des : descriptors) { //属性名称 String fieldName = des.getName(); //如果有这个属性 if (propMap.containsKey(fieldName)) { //写属性的方法 Method setter = des.getWriteMethod(); setter.invoke(bean, new Object[]{propMap.get(fieldName)}); } } } catch (Exception e) { //异常处理 System.out.println("shit"); e.printStackTrace(); } } }
备忘录角色
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; } }
调用
public class Client { public static void main(String[] args) { //定义出发起人 Originator ori = new Originator(); //定义出备忘录管理员 Caretaker caretaker = new Caretaker(); //初始化 ori.setState1("中国"); ori.setState2("强盛"); ori.setState3("繁荣"); System.out.println("===初始化状态=== " + ori); //创建一个备忘录 caretaker.setMemento(ori.createMemento()); //修改状态值 ori.setState1("软件"); ori.setState2("架构"); ori.setState3("优秀"); System.out.println(" ===修改后状态=== " + ori); //恢复一个备忘录 ori.restoreMemento(caretaker.getMemento()); System.out.println(" ===恢复后状态=== " + ori); } }
结果
===初始化状态===
state1=中国
stat2=强盛
state3=繁荣
===修改后状态===
state1=软件
stat2=架构
state3=优秀
===恢复后状态===
state1=中国
stat2=强盛
state3=繁荣
注意
如果要设计一个在运行期决定备份状态的框架,则建议采用AOP框架来实现,避免采用动态代理无谓地增加程序逻辑复杂性
再扩展:
需求:多备份的备忘录
public class Caretaker { //容纳备忘录的容器 private HashMap<String, Memento> memMap = new HashMap<String, Memento>(); public Memento getMemento(String idx) { return memMap.get(idx); } public void setMemento(String idx, Memento memento) { this.memMap.put(idx, memento); } }
调用
public class Client { public static void main(String[] args) { //定义出发起人 Originator originator = new Originator(); //定义出备忘录管理员 Caretaker caretaker = new Caretaker(); //创建两个备忘录 caretaker.setMemento("001", originator.createMemento()); caretaker.setMemento("002", originator.createMemento()); //恢复一个指定标记的备忘录 originator.restoreMemento(caretaker.getMemento("001")); } }
注意
内存溢出问题,该备份一旦产生就装入内存,没有任何销毁的意向,这是非常危险的。因此,在系统设计时,要严格限定备忘录的创建,建议增加Map的上限,否则系统很容易产生内存溢出情况
再扩展
需求:权限设为发起人可读
发起人角色
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; } }
在这里我们使用了一个新的设计方法:双接口设计,我们的一个类可以实现多个接口,在系统设计时,如果考虑对象的安全问题,则可以提供两个接口,一个是业务的正常接口,实现必要的业务逻辑,叫做宽接口;另外一个接口是一个空接口,什么方法都没有,其目的是提供给子系统外的模块访问,比如容器对象,这个叫做窄接口,由于窄接口中没有提供任何操纵数据的方法,因此相对来说比较安全。