2019独角兽企业重金招聘Python工程师标准>>>

一.备忘录模式

  1. 备忘录模式属于三种设计模式中的行为型模式(另外两种是创建型模式和结构型模式)。

  2. 定义:在不破坏封闭性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将改变了的对象恢复到原先保存的状态。

  3. 之所以需要存储改变前的对象,是因为java对象的传递是引用传递。A a1=a,a里面的东西变就等同于a1里面的东西变。

  4. 备忘录模式的结构:

    1. 发起人:负责记录当前时刻的内部状态,负责定义那些属于备忘范围的状态,负责创建和恢复备忘录数据。

    2. 备忘录:负责存储发起人对象的内部状态,在需要的时候提供发起人需要的内部状态。

    3. 管理角色:对备忘录进行管理,保存和提供备忘录。

  5. 优点:

    1. 当发起人角色中的状态改变时,有可能这是个错误的改变,我们使用备忘录模式就可以还原。

    2. 备份的状态是保存在发起人角色之外的,这样,发起人角色就不需要对哥哥备份状态进行管理。

    3. 如果有需要提供回滚操作的需求,使用备忘录模式非常合适

  6. 缺点:

    1. 在实际应用中,备忘录模式多事多状态和多备份的,发起人角色的状态需要存储到备忘录对象中,对字段的小号是比较严重的。

  7. 从设计模式角度讲:个人感觉他对六大设计模式原则的体现不是很大,只能说满足单一职责原则把,比如一个类的实例如果想要从不能备忘改为需要备忘,通过该模式,我们还是要为该类增加一个保存和恢复的方法,违背了开闭原则,client端调用的时候需要知道。为什么不直接定义一个容器,拷贝一个该对象,需要回复的时候再赋值过去呢(这样貌似又不伦不类了,因为体现不出来备忘是某个对象的能力,略纠结啊)。(欢迎大神透彻分析下)

二.测试代码

  1. 简单版测试用例:

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;}@Overridepublic 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();}}
}

转载于:https://my.oschina.net/u/2323537/blog/631874

一天一种设计模式之二-----备忘录模式相关推荐

  1. 一天一种设计模式之六-----工厂方法模式

    2019独角兽企业重金招聘Python工程师标准>>> 一.工厂方法模式 工厂方法模式属于创建型模式. 工厂方法模式定义:定义一个用于创建对象的借口,让子类决定实例化哪一个类.工厂方 ...

  2. 备战面试日记(3.3) - (设计模式.23种设计模式之结构型模式)

    本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试. 记录日期:2022.1.9 大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习. 文章 ...

  3. 备战面试日记(3.2) - (设计模式.23种设计模式之创建型模式)

    本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试. 记录日期:2022.1.6 大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习. 文章 ...

  4. 备战面试日记(3.4) - (设计模式.23种设计模式之行为型模式)

    本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试. 记录日期:2022.1.12 大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习. 文 ...

  5. 走穿java23种设计模式-15责任链模式详解

    走穿java23种设计模式-15责任链模式详解 责任链模式是一种常见的行为模式. 一.责任链模式的现实场景 习伟过生日邀请了很多朋友到KTV一起庆祝,为了增加欢乐的气氛,习伟建议大家一起玩击鼓传花的游 ...

  6. JAVA23种设计模式(2)-结构型模式7种

    JAVA23种设计模式(2)-结构型模式7种 把类结合在一起形成更大的结构 适配器模式(adapter) 一句话:将一个类的接口转换成另一种接口.让原本接口不兼容的类可以兼容 这是平时比较常见的一种模 ...

  7. 走穿java23种设计模式--18中介者模式详解

    走穿java23种设计模式–18中介者模式详解 中介者模式也称调停者模式,是一种比较简单的模式. 一.中介者模式的现实场景 蔡良因为上次表白时对方只看重他的物质方面,所以他对女朋友这个问题有点失望.因 ...

  8. 从王者荣耀看设计模式(二十二.备忘录模式)

    从王者荣耀看设计模式 一.简介 点击王者荣耀商店法术的装备栏,存在有"贤者的庇护"这一装备.在对战中,当玩家处于死亡状态时,会触发此装备的效果,能够让英雄重新复活. ┬┴┬┌─ ● ...

  9. 一天一种设计模式之五-----代理模式

    2019独角兽企业重金招聘Python工程师标准>>> 一.代理模式简介 代理模式属于结构型模式 定义:代理模式为其他对象提供一种代理以控制对这个对象的访问. 代理模式是java框架 ...

最新文章

  1. 订书机是怎样发明的?
  2. 开源内容管理系统 php mysql_「分享」7 个精致的 PHP 开源内容管理系统(CMS)
  3. Codeforces 991E. Bus Number (DFS+排列组合)
  4. RFID位置数据这么多,企业应该怎么利用?
  5. 详细解读神经网络十大误解,再也不会弄错它的事情原理
  6. qt 无法打开shell32_在Qt中用默认程序打开文件
  7. connect by prior id= pid start with id='1' 树结构查询
  8. KORG Opsix Native Mac - 音频数字合成器
  9. 谷歌浏览器的一个新特点—关于获取iframe的parent对象
  10. python如何截长图_python+selenium实现长截图
  11. lambda函数 python菜鸟教程-Python - lambda函数
  12. 毫无PS痕迹 你的第一本Photoshop书pdf
  13. 电脑如何设置u盘启动,u盘启动项设置方法
  14. Android 项目集成有米 SDK 添加广告
  15. 剑指 Offer 12-20
  16. 使用potplayer播放器看直播
  17. c语言结构体编辑学生成绩管理,C语言基于结构体的学生信息管理系统实现
  18. Eboot之函数BootloaderMain函数分析
  19. Python数据可视化 Pyecharts 制作 Tab 选项卡多图控制
  20. 我是一个假的acmer

热门文章

  1. 高级开发进阶到架构师的必要条件是什么?
  2. 腾讯云数据库智能化海量运维的建设与实践
  3. input:hidden的作用
  4. java String.replaceAll中特殊字符问题
  5. 初学Java必写的小程序。
  6. 使用Socket类接收和发送数据
  7. VMware vSphere Storage Appliance (VSA) 5.1 群集部署
  8. 【字符串替换】程序员面试金典——1.5基本字符串压缩
  9. 完全二叉树的结点数计算
  10. C++获取当前时间及计算当前时间距某个时间点的时间段