(十六)备忘录模式详解(都市异能版)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可。
凌晨两点,魔都某看守所六号牢房。
“叮咣...”
一道开门声陡然响起,牢房中的韩雨露心中一紧,明亮的眼眸看着来人,不过眼神之中的一丝惊恐却是掩饰不去。
来人正是李刚和李双江,只是此时二人眼中无神,如果仔细观察,可以看出这两个人的动作十分蹩脚,只是韩雨露此时并未注意这些细节,而是犹如等待宣判一般,惶恐不安的等待着二人说话。
“韩小姐,恭喜你,你可以出去了。”脸上勉强挤出一丝僵硬的笑容,李刚向前一步说道。
好消息从天而降,韩雨露不禁愣了一瞬间,不过很快就反应过来,诱人的小嘴没有发出声音,只是微笑的点了点头。
“肯定是爸爸救了我。”没有任何怀疑,韩雨露心中暗暗的想到。
两男一女走在看守所的道路上,途中偶尔碰到的工作人员,像是商量好了似的,全部低头不语,仿佛什么事都未发生一般,如此奇怪的场景,实在让韩雨露一时之间摸不着头脑。
按照常理来说,这些人看到有人被释放,应该不会如此安静,而且韩雨露清楚的记得当初自己被带到看守所时,眼前的二人全部都是一脸猥琐的表情盯着自己的两个山丘,而此时,二人一直走在自己前方,完全对自己视若无睹。
这倒不是韩雨露天性开放,而是换做任何人,想必都会对身边的人陡然的变化产生疑虑,况且一路上又是如此诡异,这更是让韩雨露慌乱之中,已然在不知不觉间香汗淋漓。
一路从牢房到看守所门口,徒步也仅有不到十分钟的路程,而韩雨露却觉得走的特别慢,好不容易来到了看守所门口,却是空无一人。
“爸爸为什么没来接我?”看到眼前的场景,韩雨露心中不自觉的升起一丝疑问。
“韩小姐,我们给你拦一辆出租车,你打车回去吧。”此时说话的已经换成了李双江,二人皆是面无表情的看着眼前的伊人。
魔都的出租车深夜并不好拦,不过好在运气还不错,没过多久,一辆出租车便被李双江拦下,待得韩雨露坐进去以后,李双江便扔给了司机两张毛爷爷,僵硬的说了句:“将这位小姐送到家里。”
李双江说话的同时,还专门钻到车窗里看了看司机的职照。李刚也没闲着,专门走到出租车后面,看着车牌号轻声默念了几遍,才慢慢的走回李双江身边,到此李双江才朝司机摆了摆手,示意司机出发。
韩雨露一直看着二人对自己似乎特别关心的样子,心中已经疑问满天,却是不敢多问。不过韩雨露不知道的是,当出租车刚驶出几十米之后,整个看守所的工作人员瞬间全部消失不见,犹如人间蒸发了一般,场面极其诡异。
魔都某出租屋。
“人算不如天算,天算不如不算。老子计划的这么周密,竟然还是被人给看到了。”说话之人正是小左,只不过此时的小左脸色十分不好。
经过一系列的计划之后,原本小左是打算放出韩雨露之后,自己隐身跟着韩雨露,一来可以确保韩雨露的安全,二来也可以看看韩雨露的家在何处。可是计划实施的过程中出现了一些变故,导致小左不得不让韩雨露自己做出租车回去。
原来小左在行动之前,花费了整整两个小时,才找到了一家出售蒙汗药的隐秘药店,随后小左便借助着飞行和隐身的异能,偷偷在看守所所有的饮水机里放入了大量的蒙汗药。待得所有工作人员都昏睡之后,小左才使用飞行将众人一一带回自己的出租屋。
意外就在小左带走最后两个工作人员的时候发生了,三人正在空中飞行,小左意外的发现其中一人竟然已经醒了,出乎意料的是这人醒来之后,便被高空的刺激吓得大喊大叫,导致另外一人也在途中醒来,最后还是小左在空中威胁二人,让二人自己服下剩余的蒙汗药,才制止了二人凄厉的叫喊声。
无奈之下,小左放下二人之后,便匆匆忙忙的回到看守所,凭借着之前的分身制造之法,快速的制造了一堆看守所人员的分身之后,小左就立即马不停蹄的回到了住处。小左此时已经打算在住处控制分身,他必须看着昏睡的众人,以免这坑爹的假药再闹出什么意外。
虽说距离较远的时候,控制诸多分身有些勉强,但小左还是将韩雨露顺利的放了出来,而现在小左要处理的,则是最棘手的问题,那就是自己的能力已经暴露了。
尽管小左此时完全可以干掉知情的二人,但小左毕竟不是心狠手辣之辈,如此狠毒的事情,小左自问还是做不到的。
平复了一下烦躁的心情,遇到问题的小左还是不自觉的想到了设计模式,仿佛设计模式就是现实中的问题大全,可以一解千愁一般。事实也确实如此,凭借着设计模式的理论,小左已经发掘了很多异能的特殊用法,甚至领悟新的异能,那种感觉,就犹如修炼一本内功心法一般。
“度娘啊,GOF啊,你们可要帮助下老爹啊,实在不行,我只能使出隐身恐吓一下这两个家伙了,只是这样始终难以让人安心啊。”说话的同时,小左已经开始在度娘上快速的寻找起来。
“咦?这个备忘录模式似乎和我遇到的问题有一些关系,只是为啥没有遗忘模式。我擦!”尽管有些郁闷,小左还是死死的盯着备忘录模式的定义,试图找到一点灵感。
定义:在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
“定义里说可以捕获一个对象的内部状态,在对象之外保存之后,就可以恢复该对象保存的状态。看着这个定义,总觉得似乎是和我现在的问题有点关联,可是到底应该如何使用呢?”似有所悟的看着备忘录模式的定义,小左抓着头发喃喃的说道。
“哎!管他呢,先把我现在的问题试图描述一下再说,这样比较好找出解决办法。”说着,小左便开始敲打键盘。
“如果是现在来说的话,应该只有一个类,就是表示人类,而人类应该有一个故事列表,都是从小到大的记忆。”边敲打着键盘,小左的口中依然是喋喋不休。
package com.memento; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Person { private String name; private List<String> storyList;//故事列表 public Person(String name){ this.name = name; storyList = new ArrayList<String>(); } public String getName() { return name; } public void setName(String name) { this.name = name; } //故事列表不能修改 public List<String> getStoryList() { return Collections.unmodifiableList(storyList); } //可以添加,但不可以删除 public void addStory(String history) { this.storyList.add(history); } public String toString(){ StringBuffer stringBuffer = new StringBuffer(name + "的记忆:\n"); for(String memory : storyList){ stringBuffer.append(memory).append("\n"); } return stringBuffer.toString(); } }
“这样的话,现在的情况就是两个看守所的人员都记住了我可以飞行这件事,而且还都看到了我的长相。”
package com.memento; public class Client { public static void main(String[] args) { Person personA = new Person("看守所人员A"); Person personB = new Person("看守所人员B"); //看守所人员A的记忆 personA.addStory("小时候偷换男女厕所的牌子"); personA.addStory("用裤衩上的猴皮筋做成弹弓打别人家玻璃,结果被弹了小JJ"); //看守所人员B的记忆 personB.addStory("小时候比谁尿的更高更远,我得了第一,只是不小心方向变成了直上直下,尿到了自己脸上"); personB.addStory("有一次正上课,不小心放了个屁,结果带出了点杂物,满教室都是臭味熏天"); //两个看守所人员一起经历的事 personA.addStory("有一个人竟然可以飞行,记忆中还记得他的样貌"); personB.addStory("有一个人竟然可以飞行,记忆中还记得他的样貌"); System.out.println(personA); System.out.println(personB); } }
“这个便是目前的现状了,这两个人全部记住了我的能力和长相。如果想想刚才备忘录模式的定义,说是可以将一个对象恢复到保存的状态,那么放在这里,应该是要将一个人的记忆恢复到某一个时刻把。原来如此啊,哈哈。”瞬间顿悟的小左一时间像打了鸡血似的,完全没有了刚才的一脸愁容。
“让我来看看备忘录模式的类图把,估计看完类图,解决问题的办法自然就浮现出来了。”说着小左便开始寻找度娘上备忘录模式的类图。
“看这个类图中,有着三个角色,一个便是发起人(Originator),它不仅有自己的状态,而且还负责创建一个备忘录(Memento)以及使用备忘录恢复自己的状态,而备忘录则记录了发起人的状态,至于最后一个角色管理者(Caretaker),则是用来管理备忘录的。”看着备忘录模式的类图,小左已经开始分析了起来。
“这里发起人自然便是人类(Person)了,只不过现在人类需要改变一下了,它需要提供创建一个备忘录以及使用备忘录恢复状态的操作,而备忘录和管理者都是需要新建的。只不过这里的管理者,应该就是我的灵魂了。”说道这里,小左的思路已经渐渐清晰起来,手下已经开始了代码的编写。
“先写一个备忘录的类吧,这个类如果形象的来称呼的话,应该叫记忆类。”
package com.memento; import java.util.List; //记忆类(备忘录) public class Memory { private List<String> storyList; public List<String> getStoryList() { return storyList; } public void setStoryList(List<String> storyList) { this.storyList = storyList; } }
“再来便是人(Person)类的更改了,应该是这样的。”
package com.memento; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Person { private String name; private List<String> storyList; public Person(String name){ this.name = name; storyList = new ArrayList<String>(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getStoryList() { return Collections.unmodifiableList(storyList); } public void addStory(String history) { this.storyList.add(history); } /* 新增 */ //获取记忆 public Memory getMemory(){ Memory memory = new Memory(); memory.setStoryList(new ArrayList<String>(storyList)); return memory; } //恢复记忆 public void setMemory(Memory memory){ storyList = memory.getStoryList(); } /* 新增 */ public String toString(){ StringBuffer stringBuffer = new StringBuffer(name + "的记忆:\n"); for(String memory : storyList){ stringBuffer.append(memory).append("\n"); } return stringBuffer.toString(); } }
“下面便是我的灵魂类了,它是一个记忆的管理者,可以搜集人的记忆,也可以将人的记忆强行固定或者说恢复到某一个阶段。”
package com.memento; public class Soul { private Memory memory; //抽离或者说搜集一个人的记忆 public void pullAwayMemory(Person person){ memory = person.getMemory(); } //强行将一个人的记忆固定在某一刻 public void forceFixMemory(Person person){ person.setMemory(memory); } }
““现在就让我试试备忘录模式的威力吧,哈哈。”小左得瑟的说道。
package com.memento; public class Client { public static void main(String[] args) { Soul soulA = new Soul(); Soul soulB = new Soul(); Person personA = new Person("看守所人员A"); Person personB = new Person("看守所人员B"); //看守所人员A的记忆 personA.addStory("小时候偷换男女厕所的牌子"); personA.addStory("用裤衩上的猴皮筋做成弹弓打别人家玻璃,结果被弹了小JJ"); //看守所人员B的记忆 personB.addStory("小时候比谁尿的更高更远,我得了第一,只是不小心方向变成了直上直下,尿到了自己脸上"); personB.addStory("有一次正上课,不小心放了个屁,结果带出了点杂物,满教室都是臭味熏天"); System.out.println(personA); System.out.println(personB); //两个灵魂(管理者)抽离两个人之前的记忆 soulA.pullAwayMemory(personA); soulB.pullAwayMemory(personB); //两个人看到了小左的技能和面貌 personA.addStory("有一个人竟然可以飞行,记忆中还记得他的样貌"); personB.addStory("有一个人竟然可以飞行,记忆中还记得他的样貌"); System.out.println(personA); System.out.println(personB); //强行恢复记忆 soulA.forceFixMemory(personA); soulB.forceFixMemory(personB); System.out.println(personA); System.out.println(personB); } }
“恩,备忘录模式应该叫遗忘录模式了,哈哈。这么一来,这两个人的记忆就恢复到原先没看到我之前的记忆了。”看着输出的结果,小左不禁更加得意,不过瞬间小左就脸色一变,“咦?上面使用的时候怎么出来两个灵魂?”
顿了一下,小左继续自言自语道:“这不行啊,与现实不符啊。”挠了挠头,小左继续说道:“在备忘录模式的标准实现里,一个管理者只管理了一个备忘录,所以要备份两个人的记忆的时候,就有些麻烦了。看来我还需要再稍微改一下。”说着,小左便开始匆忙的修改起来。
package com.memento; import java.util.HashMap; import java.util.Map; public class Soul { private Map<Person, Memory> memoryMap = new HashMap<Person, Memory>(); //抽离或者说搜集一个人的记忆 public void pullAwayMemory(Person person){ memoryMap.put(person, person.getMemory()); } //强行将一个人的记忆固定在某一刻 public void forceFixMemory(Person person){ if (memoryMap.containsKey(person)) { person.setMemory(memoryMap.get(person)); } } }
“让我的灵魂可以搜集多个人的记忆,应该就可以解决问题了。这下再试一下吧。”
package com.memento; public class Client { public static void main(String[] args) { Soul soul = new Soul(); Person personA = new Person("看守所人员A"); Person personB = new Person("看守所人员B"); //看守所人员A的记忆 personA.addStory("小时候偷换男女厕所的牌子"); personA.addStory("用裤衩上的猴皮筋做成弹弓打别人家玻璃,结果被弹了小JJ"); //看守所人员B的记忆 personB.addStory("小时候比谁尿的更高更远,我得了第一,只是不小心方向变成了直上直下,尿到了自己脸上"); personB.addStory("有一次正上课,不小心放了个屁,结果带出了点杂物,满教室都是臭味熏天"); System.out.println(personA); System.out.println(personB); //灵魂(管理者)抽离两个人之前的记忆 soul.pullAwayMemory(personA); soul.pullAwayMemory(personB); //两个人看到了小左的技能和面貌 personA.addStory("有一个人竟然可以飞行,记忆中还记得他的样貌"); personB.addStory("有一个人竟然可以飞行,记忆中还记得他的样貌"); System.out.println(personA); System.out.println(personB); //强行恢复记忆 soul.forceFixMemory(personA); soul.forceFixMemory(personB); System.out.println(personA); System.out.println(personB); } }
“现在的效果应该和刚才一样,不过是灵魂稍微改变了一下而已。不过看起来仍然是有些问题啊,这样的使用方式,我必须得在两个人没有看到我的时候抽离两个人的记忆,然后再恢复回去,可惜现在已经晚了。”突然意识到了另外一个问题,小左已然有些郁闷了。
“还是让我先来总结一下备忘录模式的特点吧,看能不能找到其它的办法。”一时之间想不起来对策,小左决定先总结一下备忘录模式的特点。
对于现在的情况来说,备忘录模式应该有以下几点好处。
1、人类可以将自己的记忆保存在外部,使得备份的功能不会影响人类本身,而人类则只需要提供获取记忆和恢复记忆的方法。
2、对于人类记忆的备份与恢复,人类自身不需要关心,而是使用灵魂的人关心,在这里,就是指小左本人了。
3、如果一个人的记忆丧失或出现问题,可以很轻松的恢复到原来的记忆。
如果换成专业点的语言来说的话,则应该是以下几点了。
1、发起人备份自己的状态不需要自己管理,可以备份到外部,这样可以很好的保持封装的边界,这样做的意义在于可以给外部提供一个简单的操作该对象内部状态的接口。保持封装的边界这应该算是最重要的优点了。
2、发起人状态的备份与恢复,发起人自身不需要管理与操作,而是由客户端自行按需要处理。
3、如果发起人的状态出现问题,可以很轻松的恢复。
参照刚才备忘录模式的使用,备忘录模式显然是有缺点的,应该有以下几点。
1、如果一个人岁数比较大,记忆比较多的话,全部备份会让储存记忆的灵魂压力很大。
2、由于记忆是由人类自己提供给灵魂的,所以灵魂在储存记忆的时候可能一股脑储存,无法预测一个人的记忆是否庞大。
3、如果恢复人的记忆成功率较低的话,使用备忘录模式可能会导致恢复失败,这样的话可能会使人的记忆处于不正确的状态,比如缺失或者记忆混乱。
这些缺点如果换成专业点的语言来说的话,则是以下几点。
1、如果全部备份发起人的状态,或者其中有占用内存较大的属性(比如一个长数组),则会让备忘录模式的使用代价昂贵。
2、由于备份的信息是由发起人自己提供的,所以管理者无法预知备份的信息的大小,所以在客户端使用时,可能一个操作占用了很大的内存,但客户端并不知晓。
3、当发起人的状态改变的时候,有可能这个状态无效。如果状态改变的成功率不高的话,可以采取“假如”协议模式。“假如”的意思是指,我们将一直假如状态的改变会失败,从而对此做出一系列准备的工作。不过很明显,如果状态改变的成功率很高,则这样做的收益甚微。
“感觉备忘录模式最大的缺点就是备份的信息所占用的资源可能会很庞大,这直接导致的就是我的灵魂压力颇大啊。不过还有一点,就是在使用备忘录模式的时候,必须要能关注一个对象整个状态历史,才可以使用。就是因为这个,所以现在无法将两个人的记忆恢复到见到我之前了,因为我根本没有备份他们之前的记忆啊。”
想到这个,小左不禁郁闷非常,不过片刻之后,小左还是迅速的调整好了心态,似有所悟的说道:“不过这倒算不上缺点,只能说是使用备忘录模式的前提。”
“还是看一下类图把,看看有没有什么变通的方式。”
“现在的类图与标准的备忘录模式有些出入,一个是其中一对一的聚合关系已经被我改成了一对多,还有一个就是灵魂类对人类的依赖关系,这都是我针对现实状况对设计模式做出的调整。尽管已经对现实情况做出了相应的调整,不过关于两个人记忆备份的问题依旧是看不出来什么解决方案啊。”
略微一顿,小左叹了口气,继续暗暗的摇头道:“看来是没有办法了,只能退而求其次。虽然你们会忘掉所有的过往,不过我会想办法弥补你们的。”
魔都某看守所,所长办公室。
“你们两个怎么回事,不想活了是吧。”一个满脸胡茬的中年人,此时正冲着面前的二人大发雷霆。
“所长,我们没有私自释放韩小姐啊。实在是冤枉啊...”说话的正是李刚,只不过此时,李刚与身边的李双江都是一脸憋屈的表情。
“放NMD狗臭屁!这监控录像里就是你们两个把人给放走了,你现在跟我说你们没有?”听到李刚的无力辩解,中年人更加怒气冲天,大爆粗口的骂道。
就在此时,一个身材瘦小的青年突然闯了进来,中年所长一看便认出了此人,正是看守所里的工作人员小赵,看到小赵不打招呼就硬闯进来,正在气头上的中年所长自然是怒气更甚,愤怒的吼道:“你这个家伙,什么事不打招呼就进来了。先给老子滚出去。”
“你说话声音这么大干嘛,吵着人家了。傻X,嘿嘿...”小赵像是不知道中年所长的愤怒一般,傻笑着说道。
没有料到会出现这样的情况,中年所长顿时一脸铁青,指着李刚和李双江二人,面目狰狞的说道:“去!给我拖出去狠狠的打,一会回来再跟你们俩算账。NND,我看你们是都不想活了。”