《设计模式之禅》--备忘录扩展:多状态的备忘录
接上篇《设计模式之禅》--备忘录扩展: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 + "\nstat2=" + state2 + "\nstate3=" + 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("===初始化状态===\n" + ori); //创建一个备忘录 caretaker.setMemento(ori.createMemento()); //修改状态值 ori.setState1("软件"); ori.setState2("架构"); ori.setState3("优秀"); System.out.println("\n===修改后状态===\n" + ori); //恢复一个备忘录 ori.restoreMemento(caretaker.getMemento()); System.out.println("\n===恢复后状态===\n" + 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; } }
在这里我们使用了一个新的设计方法:双接口设计,我们的一个类可以实现多个接口,在系统设计时,如果考虑对象的安全问题,则可以提供两个接口,一个是业务的正常接口,实现必要的业务逻辑,叫做宽接口;另外一个接口是一个空接口,什么方法都没有,其目的是提供给子系统外的模块访问,比如容器对象,这个叫做窄接口,由于窄接口中没有提供任何操纵数据的方法,因此相对来说比较安全。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2016-02-12 java基本数据类型及相互间的转换