备忘录模式---给你一瓶后悔药

来源:互联网 发布:买情侣装的淘宝店 编辑:程序博客网 时间: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
原创粉丝点击