备忘录模式---给你一瓶后悔药
来源:互联网 发布:买情侣装的淘宝店 编辑:程序博客网 时间:2024/04/24 11:54
声明:文章内容根据大牛博客的内容,自己理解后,给自己做的学习笔记,文末会附上大牛博客地址链接。有需要沟通交流的可加我QQ群:425120333 在生活中,每个人都应该有这样的经历:如果我当初那样做就好了,也不会出现现在的情况。这里的如果怎样都是对当初所选择的做法的后悔, 如果当初多看点书,如果当初都努力下,如果......太多太多的如果了,可是现实世界没有后悔药,过去了就已经成为事实,改变不了。在现实世界 虽然没有后悔药,但是在代码中有,而这也是今天要介绍的主角——备忘录模式。其中又可以分为:标准版备忘录、clone版备忘录、多状态备忘录、 多备份的备忘录、私有备忘录等。 这里先描述下场景,然后将各种情况的备忘录给实现出来。场景:A的同事生日了,A要送份礼物,可是A不知道同事喜欢什么,如果送了同事喜欢的礼物 当然是皆大欢喜,如果送了不怎么喜欢的,A希望可以回到送礼之前的状态,重新选择礼物。这里就是一个很简单的场景就是要保证A一定能 送同事喜欢的礼物,为了保证这一点,只能是在A送错的情况下,能后悔重新送就可以了。 首先是标准版的备忘录:
public class ChooseGift { public static void main(String[] args) { APerson person = new APerson(); MementoManager manager = new MementoManager(); System.out.println("未送礼前的状态:" + person.getGiftName()); manager.setMemento(person.createMemento()); person.setGiftName("不喜欢的礼物"); System.out.println("送错了礼物的状态:" + person.getGiftName()); person.restore(manager.getMemento()); System.out.println("发现了送错了礼物,吃下后悔药,回到开始状态 :" + person.getGiftName()); }}class APerson { private String giftName = "礼物未选择"; public String getGiftName() { return giftName; } public void setGiftName(String giftName) { this.giftName = giftName; } public Memento createMemento() { return new Memento(this.giftName); } public void restore(Memento memento) { this.setGiftName(memento.getGiftName()); }}class Memento { private String giftName; public Memento(String giftName) { this.giftName = giftName; } public String getGiftName() { return this.giftName; } public void setGiftName(String giftName) { this.giftName = giftName; }}class MementoManager { Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; }}
客户端输出:
未送礼前的状态:礼物未选择
送错了礼物的状态:不喜欢的礼物
发现了送错了礼物,吃下后悔药,回到开始状态 :礼物未选择
clone版备忘录:
public class ChooseGift { public static void main(String[] args) { APerson person = new APerson(); System.out.println("未送礼前的状态:" + person.getGiftName()); person.createMemento(); person.setGiftName("不喜欢的礼物"); System.out.println("送错了礼物的状态:" + person.getGiftName()); person.restore(); System.out.println("发现了送错了礼物,吃下后悔药,回到开始状态 :" + person.getGiftName()); }}class APerson implements Cloneable { private APerson person; private String giftName = "礼物未选择"; public String getGiftName() { return giftName; } public void setGiftName(String giftName) { this.giftName = giftName; } public void createMemento() { this.person = this.clone(); } public void restore() { this.setGiftName(person.getGiftName()); } @Override protected APerson clone() { try { return (APerson) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } }}
控制台输出:
未送礼前的状态:礼物未选择
送错了礼物的状态:不喜欢的礼物
clone版备忘录模式相比较于标准版代码是简洁了一些,不过其中有两点问题,一是、clone是整个对象的复制,而有时,只需保存一两个状态值,没必要存储整个对象。二是、在使用clone时,需注意下深克隆和浅克隆的情况。(参考链接:http://blog.csdn.net/hanlipenghanlipeng/article/details/52120741) 私有备忘录:
public class ChooseGift { public static void main(String[] args) { APerson person = new APerson(); MementoManager manager = new MementoManager(); System.out.println("未送礼前的状态:" + person.getGiftName()); manager.setMemento(person.createMemento()); person.setGiftName("不喜欢的礼物"); System.out.println("送错了礼物的状态:" + person.getGiftName()); person.restore(manager.getMemento()); System.out.println("发现了送错了礼物,吃下后悔药,回到开始状态 :" + person.getGiftName()); }}class APerson { private String giftName = "礼物未选择"; public String getGiftName() { return giftName; } public void setGiftName(String giftName) { this.giftName = giftName; } public MementoImpl createMemento() { return new Memento(this.giftName); } public void restore(MementoImpl mementoImpl) { Memento memento = (Memento) mementoImpl; this.setGiftName(memento.getGiftName()); } private class Memento implements MementoImpl { private String giftName; private Memento(String giftName) { this.giftName = giftName; } private String getGiftName() { return this.giftName; } }}interface MementoImpl {}class MementoManager { MementoImpl memento; public MementoImpl getMemento() { return memento; } public void setMemento(MementoImpl memento) { this.memento = memento; }}
控制台输出:
未送礼前的状态:礼物未选择
送错了礼物的状态:不喜欢的礼物
发现了送错了礼物,吃下后悔药,回到开始状态 :礼物未选择
这里使用了一个新的设计模式:双接口设计,我们设计的一个类可以实现多个接口,在系统设计时,如果考虑对象的安全问题,则可以提供两个接口,一个是业务的正常接口,实现必要的业务逻辑(平时使用的普通接口),叫做宽接口;另一个接口是空接口,什么方法都没有,其目的是提供给子系统外的模块访问,比如容器对象,这个叫做窄接口,由于窄接口没有提供任何操纵数据的方法,因此相对来说比较安全。(这一段引自设计模式之禅) 上述描述的都是依赖当前的场景而给出的解决办法,但是需要知道一点是需求是会变的,如果同事要求来的时候顺便带个蛋糕,而A又忘了要到什么口味的,这时就要求A同时存在两个初始信息,蛋糕信息和礼物信息。虽然可以参考原先的继续构建一个蛋糕的备忘录,但如果后续还增加,那增加的备忘录就太多了,这时多状态的备忘录就派上用处了。 多状态备忘录模式:
public class ChooseGift { public static void main(String[] args) { APerson person = new APerson(); MementoManager manager = new MementoManager(); System.out.println("未送礼前的状态:" + person.getGiftName() + "---" + person.getCakeInfo()); manager.setMemento(person.createMemento()); person.setGiftName("不喜欢的礼物"); person.setCakeInfo("错误口味的蛋糕"); System.out.println("送错了礼物的状态:" + person.getGiftName() + "---" + person.getCakeInfo()); person.restore(manager.getMemento()); System.out.println("发现了送错了礼物,吃下后悔药,回到开始状态 :" + person.getGiftName() + "---" + person.getCakeInfo()); }}class APerson { private String giftName = "礼物未选择"; private String cakeInfo = "蛋糕未选择"; public String getGiftName() { return giftName; } public void setGiftName(String giftName) { this.giftName = giftName; } public String getCakeInfo() { return cakeInfo; } public void setCakeInfo(String cakeInfo) { this.cakeInfo = cakeInfo; } public Memento createMemento() { Map<String, Object> map = BeanUtil.getFieldInfoMap(this); return new Memento(map); } public void restore(Memento memento) { this.setGiftName((String) memento.getMap().get("giftName")); this.setCakeInfo((String) memento.getMap().get("cakeInfo")); }}class Memento { private Map<String, Object> map; public Memento(Map<String, Object> map) { this.map = map; } public Map<String, Object> getMap() { return this.map; }}class MementoManager { Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; }}class BeanUtil { public static Map<String, Object> getFieldInfoMap(Object obj) { Map<String, Object> map = new HashMap<String, Object>(); String[] fieldNameArray = getFieldNameArray(obj); for (String fieldName : fieldNameArray) { map.put(fieldName, getValue(fieldName, obj)); } return map; } /** * @introduce:根据属性名获取相应的值 */ private static Object getValue(String fieldName, Object obj) { try { String sign = fieldName.substring(0, 1).toUpperCase(); String methodName = "get" + sign + fieldName.substring(1); Method method = obj.getClass().getMethod(methodName, new Class[] {}); Object object = method.invoke(obj, new Object[] {}); return object; } catch (Exception e) { e.printStackTrace(); return null; } } /** * @introduce:获取对象的所有属性名 */ private static String[] getFieldNameArray(Object obj) { Field[] array = obj.getClass().getDeclaredFields(); String[] fieldNameArray = new String[array.length]; for (int i = 0; i < array.length; i++) { fieldNameArray[i] = array[i].getName(); } return fieldNameArray; }}
控制台输出:
未送礼前的状态:礼物未选择—蛋糕未选择
送错了礼物的状态:不喜欢的礼物—错误口味的蛋糕
发现了送错了礼物,吃下后悔药,回到开始状态 :礼物未选择—蛋糕未选择
多备份的备忘录模式就是A买了一个礼物,就保存一个备忘录,可能一开始这些礼物,同事都不喜欢,后来同事都其中一个感兴趣了,只要回到当初保存的备忘录中即可,这个比较简单只是在MementoManager中本来保存的信息改为保存一个map<String,Memento>,将各个需要的备忘都存放进去,用的时候取相应的即可。这里有个问题就是内存可能溢出,所以保存备忘录时要注意。 参考大牛博客:http://www.cnblogs.com/zuoxiaolong/p/pattern17.html
0 0
- 备忘录模式---给你一瓶后悔药
- 备忘录模式——编程中的后悔药
- 世界上没有后悔药,但我们给你预防后悔!
- 备忘录模式
- 备忘录模式
- 备忘录模式
- 备忘录模式
- 备忘录模式
- 备忘录模式
- 备忘录模式
- 备忘录模式
- 备忘录模式
- 备忘录模式
- 备忘录模式
- 备忘录模式
- 备忘录模式
- 备忘录模式
- 备忘录模式
- MySQL Packet for query is too large 问题及解决方案
- nginx 负载均衡策略及配置
- 8天学通MongoDB——第五天 主从复制
- 淘宝详情界面的头部视图被覆盖的效果
- python读文件或文件夹计算idf
- 备忘录模式---给你一瓶后悔药
- 机器学习资料总结
- git回退到以前某个版本
- 自建钥匙串管理自己应用的证书和key
- [JSOI2008] 球形空间产生器
- C# Newtonsoft.Json 操作
- HTML5学习笔记14-Canvas绘制渐变图形与绘制变形图形
- React 入门实例教程
- 8天学通MongoDB——第四天 索引操作