备忘录(Memento)模式:又叫做快照模式(Snapshot Pattern)或Token模式,属于行为模式。在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
备忘录模式有如下结构图:
备忘录模式涉及角色如下:
发起人(Originator):负责创建一个备忘录Memento,用以记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。Originator可以根据需要决定Memento存储自己的哪些内部状态。
备忘录(Memento):负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator却可看到备忘录的宽接口,允许它访问返回到先前状态所需要的所有数据。
管理者(Caretaker):负责备忘录Memento,不能对Memento的内容进行访问或者操作。
对上面结构图的代码模拟:
package memento; /** * *作者:alaric *时间:2013-8-25下午2:04:27 *描述:备忘录角色 */ public 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; } }
package memento; /** * *作者:alaric *时间:2013-8-25下午2:48:32 *描述:发起人 */ public class Originator { private String state; public Memento createMemento(){ return new Memento(state); } /** * *作者:alaric *时间:2013-8-25下午4:05:39 *描述:还原 */ public void restoreMemento(Memento memento){ this.state = memento.getState(); } public String getState() { return state; } public void setState(String state) { this.state = state; } }
package memento; /** * *作者:alaric *时间:2013-8-25下午2:48:05 *描述:管理者 */ public class Caretaker { private Memento memento; /** * *作者:alaric *时间:2013-8-25下午3:47:18 *描述:取值 */ public Memento retrieveMemento(){ return memento; } /** * *作者:alaric *时间:2013-8-25下午4:05:01 *描述:设置 */ public void saveMemento(Memento memento){ this.memento = memento; } }
package memento; /** * *作者:alaric *时间:2013-8-25下午2:03:49 *描述:测试类 */ public class Client { private static Originator o = new Originator(); private static Caretaker c = new Caretaker(); /** *作者:alaric *时间:2013-8-25下午2:03:43 *描述: */ public static void main(String[] args) { //改变发起人的状态 o.setState("on"); //创建备忘录对象,并保持于管理保持 c.saveMemento(o.createMemento()); //改变发起人的状态 o.setState("off"); //还原状态 o.restoreMemento(c.retrieveMemento()); } }对于上述描述中,客户端语句o.createMemento()得到备忘录后,是可以直接获取备忘录中信息的,因为备忘录类没有提供窄接口,这样就破坏了原有的封装性。这种设计备忘录角色的内部所存状态对所有对象是公开的,所以叫做"白箱"实现。有白箱就有黑箱,“黑箱”的实现方式就是利用java双接口的方式来隔离不同的对象访问的。
什么是双接口?就是一个类实现两个接口,不同的类看到的是不同的类型,就像蝙蝠一样,在老鼠一块他就展现的是老鼠的接口;在鸟一块就展现的是鸟的接口。
对于备忘录来说实现双接口,给发起人(Originator)角色展现宽接口,给管理者管理者(Caretaker)提供窄接口。宽接口由Memento本身就可以展现,窄接口只是个标识接口,不提供任何操作的方法。接下来看看如何用双接口方式“ 黑箱”实现。
首先以Memento以标识接口方式提供给除了发起人角色以外的对象,然后把Memento类作为Originaator的内部类,并用private来修饰,保证外部无法操作此类。结构图如下:
描述代码如下:
package memento.black; /** * *作者:alaric *时间:2013-8-25下午6:12:48 *描述:标识接口 */ public interface IMemento { }
package memento.black; /** * *作者:alaric *时间:2013-8-25下午2:48:32 *描述:发起人 */ public class Originator { private String state; /** * *作者:alaric *时间:2013-8-25下午6:18:36 *描述:穿件备忘录 */ public IMemento createMemento(){ return (IMemento) new Memento(state); } /** * *作者:alaric *时间:2013-8-25下午4:05:39 *描述:还原 */ public void restoreMemento(IMemento memento){ Memento m = (Memento) memento; setState(m.getState()); } public String getState() { return state; } public void setState(String state) { this.state = state; System.out.println("current state:"+state); } /** * *作者:alaric *时间:2013-8-25下午9:22:02 *描述:内部类 */ public class Memento implements IMemento{ private String state; public Memento(String state){ this.state = state; } public String getState() { return state; } public void setState(String state) { this.state = state; } } }
package memento.black; /** * *作者:alaric *时间:2013-8-25下午2:48:05 *描述:管理者 */ public class Caretaker { private IMemento memento; /** * *作者:alaric *时间:2013-8-25下午3:47:18 *描述:取值 */ public IMemento retrieveMemento(){ return memento; } /** * *作者:alaric *时间:2013-8-25下午4:05:01 *描述:设值 */ public void saveMemento(IMemento memento){ this.memento = memento; } }
package memento.black; /** * *作者:alaric *时间:2013-8-25下午2:03:49 *描述:测试类 */ public class Client { private static Originator o = new Originator(); private static Caretaker c = new Caretaker(); /** *作者:alaric *时间:2013-8-25下午2:03:43 *描述: */ public static void main(String[] args) { //改变发起人的状态 o.setState("on"); //创建备忘录对象,并保持于管理保持 c.saveMemento(o.createMemento()); //改变发起人的状态 o.setState("off"); //还原状态 o.restoreMemento(c.retrieveMemento()); } }运行结果:
current state:on
current state:off
current state:on
举个栗子,数据库系统设定一天一个全备,10分钟一个差备,当数据库系统出现问题的时候,就可以还原最近的一个备份。数据库的备份是一个黑箱的,在没还原之前,一个备份文件我们看不出里面都是什么样的数据,所以这里用黑箱实现来描述,先给出类结构图如下:
描述代码如下:
package memento.example; /** * *作者:alaric *时间:2013-8-25下午6:12:48 *描述:标识接口 */ public interface IMemento { }
package memento.example; /** * *作者:alaric *时间:2013-8-25下午2:48:32 *描述:数据库系统(发起人角色) */ public class DatabaseServer { private boolean isUseable; /** * *作者:alaric *时间:2013-8-25下午6:18:36 *描述:穿件备忘录 */ public IMemento createMemento(){ return (IMemento) new Memento(isUseable); } /** * *作者:alaric *时间:2013-8-25下午4:05:39 *描述:还原 */ public boolean restoreMemento(IMemento memento){ Memento m = (Memento) memento; setUseable(m.isUseable()); return this.isUseable; } public boolean isUseable() { return isUseable; } public void setUseable(boolean isUseable) { this.isUseable = isUseable; System.out.println("DB state useable is: "+isUseable); } /** * *作者:alaric *时间:2013-8-25下午9:22:02 *描述:内部类 */ public class Memento implements IMemento{ private boolean isUseable; public Memento(boolean isUseable) { super(); this.isUseable = isUseable; } public boolean isUseable() { return isUseable; } public void setUseable(boolean isUseable) { this.isUseable = isUseable; } } }
package memento.example; import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * *作者:alaric *时间:2013-8-25下午2:48:05 *描述:备份服务器(管理者) */ public class BackupsServer { private DatabaseServer dbServer ;//增强管理者的功能,把发起人的操作放在这里 private Map<Long,IMemento> mementos ;//用一个map来对数据库服务多点备份 public BackupsServer(DatabaseServer dbServer) { super(); this.dbServer = dbServer; mementos = new ConcurrentHashMap<>(); } /** * *作者:alaric *时间:2013-8-25下午3:47:18 *描述:还原 */ public void retrieveMemento(){ Iterator<Long> it = mementos.keySet().iterator(); //还原到最近一个可用的状态 while(it.hasNext()){ Long key = it.next(); IMemento val = mementos.get(key); boolean isUseable = dbServer.restoreMemento(val); if(isUseable){ break; } } } /** * *作者:alaric *时间:2013-8-25下午4:05:01 *描述:备份 */ public void createMemento(){ IMemento memento = dbServer.createMemento(); this.mementos.put(new Date().getTime(), memento); } }
package memento.example; import java.util.Map; import memento.Caretaker; /** * *作者:alaric *时间:2013-8-25下午2:03:49 *描述:测试类 */ public class Client { private static DatabaseServer dbServer = new DatabaseServer(); private static BackupsServer backupServer = new BackupsServer(dbServer); /** *作者:alaric *时间:2013-8-25下午2:03:43 *描述: * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { //数据库系统设置可用状态 dbServer.setUseable(true); //备份 backupServer.createMemento(); //1秒钟备份一次 Thread.sleep(1000); dbServer.setUseable(true); backupServer.createMemento(); Thread.sleep(1000); dbServer.setUseable(true); backupServer.createMemento(); Thread.sleep(1000); //设置系统故障 dbServer.setUseable(false); //系统故障立即还原到最近一次可用状态 System.out.println("------系统还原-----"); backupServer.retrieveMemento(); } }运行结果:
DB state useable is: true
DB state useable is: true
DB state useable is: true
DB state useable is: false
------系统还原-----
DB state useable is: true
上述代码利用黑箱实现方式模拟了数据库备份还原过程。备忘录模式优点是简化了发起人(Originator)类,它不在需要管理负责备份一个副本在自己内部,当发起人内部状态失效时,可以用外部状态来还原。备忘录模式的缺点是完整保存发起人状态在整个过程中,备忘录角色的资源消耗可能很大,还有就是管理者不知道资源到底多大,外部能不能承担,外部无法预料,也无法给用户一个提醒。
设计模式系列目录:
相关推荐
**Java设计模式——备忘录模式详解** 备忘录模式是一种行为设计模式,它允许对象在不破坏封装性的前提下捕获并存储其内部状态,以便稍后恢复到该状态。这种模式常用于在游戏中保存进度、撤销/重做操作、以及在复杂...
本资料“《java设计模式》课后习题模拟试题解答——刘伟.zip”主要涵盖了Java设计模式的学习与应用,特别是针对刘伟教授的相关课程的课后习题及模拟试题的解答。 设计模式分为三大类:创建型、结构型和行为型模式。...
《Java设计模式》是刘伟老师的一本经典教材,它深入浅出地讲解了软件设计中的重要概念——设计模式。设计模式是经验丰富的开发者在解决常见问题时总结出的通用解决方案,是软件开发中的智慧结晶。这本书的课后习题和...
java和设计模式ppt包含工厂模式、建造模式、原始模型模式、单例模式、结构模式、适配器、桥梁模式、合成模式、装饰模式、门面模式、享元模式、代理模式、行为模式、解释器模式、迭代子模式、调停者模式、备忘录模式...
【标题】"s2sh框架实例——个人备忘录系统源码" 提供了一个学习和研究Web开发的宝贵资源,特别适合对Java Web技术感兴趣的初学者。S2SH是Struts2、Spring和Hibernate三个开源框架的组合,是Java领域广泛应用的MVC...
【备忘录模式(Memento Pattern)】是一种设计模式,主要目的是为了在不破坏对象封装性的前提下,能够保存和恢复对象的内部状态。这种模式常用于实现撤销/重做功能,例如在文本编辑器、游戏或数据库管理系统中。通过...
目录: 前 言 第一部分 大旗不挥,谁敢冲锋——热身篇 第1章 单一职责原则 1.1 我是“牛”类,我可以担任多职吗 1.2 绝杀技,打破你的传统思维 1.3 我单纯,所以我快乐 1.4 最佳实践 ...附录:23个设计模式
### Java设计模式经典教程知识点概览 #### 一、设计模式概述 设计模式是一种软件设计方法,它为软件开发者提供了一种标准化的方式去解决常见的软件设计问题。设计模式的使用可以提高代码的可读性和可维护性,同时...
根据提供的标题、描述以及部分内容,本文将深入探讨Java设计模式,并着重分析23种常见的设计模式,以帮助Java程序员更好地理解和应用这些模式。 ### Java设计模式概述 Java设计模式是面向对象软件设计的一种通用可...
《Java与模式》是闫宏大师的一部经典之作,它将古老的哲学智慧——道德经的智慧,巧妙地融入到现代编程语言Java的设计模式之中。这本书不仅深入浅出地讲解了23种经典的设计模式,还提供了丰富的实践案例,旨在帮助...
备忘录模式是一种行为设计模式,它能在不破坏封装的前提下捕获一个对象的内部状态,并在该对象之外保存这个状态。这样之后就可以将该对象恢复到原先保存的状态。 ##### 模式背景 在开发过程中,我们经常会遇到需要...
### Java设计模式(1)——理解与应用 #### 一、设计模式概述 设计模式是在软件工程领域中,为了应对特定问题或情境而形成的最佳实践集合。这些模式可以帮助开发者更高效地解决常见问题,提高代码的可重用性和可...
### JAVA设计模式总结之23种设计模式及六大原则 #### 一、设计模式之六大原则 ##### 总原则:开闭原则(Open Close Principle) 开闭原则是设计模式中最核心的原则之一,它强调的是软件实体(类、模块、函数等)...
设计模式是软件工程中的一种最佳实践,它是在特定上下文中解决常见问题的模板或蓝图。...通过阅读《设计模式——Java语言中的应用》这本书,你可以更深入地学习和掌握这些模式的细节及其在实际开发中的应用。
《JAVA设计模式(中文).chm》是一部专为Java开发者准备的设计模式指南,它深入浅出地阐述了软件工程中的重要概念——设计模式。设计模式是解决常见编程问题的成熟解决方案,是经验丰富的开发者们在实践中总结出的最佳...
#### 前言:迈向精通之路——设计模式的重要性 在软件开发领域,设计模式被视为提升代码质量和可维护性的关键工具。本文将深入探讨Java和Android开发中常用的设计模式,并结合实际案例进行解析,帮助读者理解和应用...
"Java设计模式-图解-附代码"可能会通过图形化的方式,帮助读者直观理解各种设计模式,并提供了具体的Java代码示例,这对于初学者来说尤其有帮助。书中可能涵盖了23种经典设计模式,如工厂模式、建造者模式、原型模式...
设计模式趣味学习(复习) 设计模式趣味学习(复习) 设计模式与足球(一) 设计模式与足球(二) 设计模式与足球(三) 设计模式与足球(四) 设计模式综合应用实例 设计模式综合应用实例 多人联机射击游戏 多人...