一、引子
俗话说:世上难买后悔药。所以凡事讲究个“三思而后行”,但总常见有人做“痛心疾首”状:当初我要是……。如果真的有《大话西游》中能时光倒流的“月光宝盒”,那这世上也许会少一些伤感与后悔——当然这只能是痴人说梦了。
但是在我们手指下的程序世界里,却有的后悔药买。今天我们要讲的备忘录模式便是程序世界里的“月光宝盒”。
二、定义与结构
备忘录(Memento)模式又称标记(Token)模式。GOF给备忘录模式的定义为:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
在讲命令模式的时候,我们曾经提到利用中间的命令角色可以实现undo、redo的功能。从定义可以看出备忘录模式是专门来存放对象历史状态的,这对于很好的实现undo、redo功能有很大的帮助。所以在命令模式中undo、redo功能可以配合备忘录模式来实现。
其实单就实现保存一个对象在某一时刻的状态的功能,还是很简单的——将对象中要保存的属性放到一个专门管理备份的对象中,需要的时候则调用约定好的方法
将备份的属性放回到原来的对象中去。但是你要好好看看为了能让你的备份对象访问到原对象中的属性,是否意味着你就要全部公开或者包内公开对象原本私有的属
性呢?如果你的做法已经破坏了封装,那么就要考虑重构一下了。
备忘录模式只是GOF对“恢复对象某时的原有状态”这一问题提出的通用方案。因此在如何保持封装性上——由于受到语言特性等因素的影响,备忘录模式并没有详细描述,只是基于C++阐述了思路。那么基于Java的应用应该怎样来保持封装呢?我们将在实现一节里面讨论。
来看下“月光宝盒”备忘录模式的组成部分:
1)
备忘录(Memento)角色:备忘录角色存储“备忘发起角色”的内部状态。“备忘发起角色”根据需要决定备忘录角色存储“备忘发起角色”的哪些内部状
态。为了防止“备忘发起角色”以外的其他对象访问备忘录。备忘录实际上有两个接口,“备忘录管理者角色”只能看到备忘录提供的窄接口——对于备忘录角色中
存放的属性是不可见的。“备忘发起角色”则能够看到一个宽接口——能够得到自己放入备忘录角色中属性。
2) 备忘发起(Originator)角色:“备忘发起角色”创建一个备忘录,用以记录当前时刻它的内部状态。在需要时使用备忘录恢复内部状态。
3) 备忘录管理者(Caretaker)角色:负责保存好备忘录。不能对备忘录的内容进行操作或检查。
备忘录模式的类图真是再简单不过了:
三、举例
按照定义中的要求,备忘录角色要保持完整的封装。最好的情况便是:备忘录角色只应该暴露操作内部存储属性的的接口给“备忘发起角色”。而对于其他角色则
是不可见的。GOF在书中以C++为例进行了探讨。但是在Java中没有提供类似于C++中友元的概念。在Java中怎样才能保持备忘录角色的封装呢?
下面对三种在Java中可保存封装的方法进行探讨。
第一种就是采用两个不同的接口类来限制访问权限。这两个接口类中,一个提供比较完备的操作状态的方法,我们称它为宽接口;而另一个则可以只是一个标示,
我们称它为窄接口。备忘录角色要实现这两个接口类。这样对于“备忘发起角色”采用宽接口进行访问,而对于其他的角色或者对象则采用窄接口进行访问。
这种实现比较简单,但是需要人为的进行规范约束——而这往往是没有力度的。
第二种方法便很好的解决了第一种的缺陷:采用内部类来控制访问权限。将备忘录角色作为“备忘发起角色”的一个私有内部类。好处我不详细解释了,看看代码吧就明白了。下面的代码是一个完整的备忘录模式的教学程序。它便采用了第二种方法来实现备忘录模式。
还有一点值得指出的是,在下面的代码中,对于客户程序来说“备忘录管理者角色”是不可见的,这样简化了客户程序使用备忘录模式的难度。下面采用“备忘发起角色”来调用访问“备忘录管理者角色”,也可以参考门面模式在客户程序与备忘录角色之间添加一个门面角色。
class Originator{
//这个是要保存的状态
private int state= 90;
//保持一个“备忘录管理者角色”的对象
private Caretaker c = new Caretaker();
//读取备忘录角色以恢复以前的状态
public void setMemento(){
Memento memento = (Memento)c.getMemento();
state = memento.getState();
System.out.println("the state is "+state+" now");
}
//创建一个备忘录角色,并将当前状态属性存入,托给“备忘录管理者角色”存放。
public void createMemento(){
c.saveMemento(new Memento(state));
}
//this is other business methods...
//they maybe modify the attribute state
public void modifyState4Test(int m){
state = m;
System.out.println("the state is "+state+" now");
}
//作为私有内部类的备忘录角色,它实现了窄接口,可以看到在第二种方法中宽接口已经不再需要
//注意:里面的属性和方法都是私有的
private class Memento implements MementoIF{
private int state ;
private Memento(int state){
this.state = state ;
}
private int getState(){
return state;
}
}
}
//测试代码——客户程序
public class TestInnerClass{
public static void main(String[] args){
Originator o = new Originator();
o.createMemento();
o.modifyState4Test(80);
o.setMemento();
}
}
//窄接口
interface MementoIF{}
//“备忘录管理者角色”
class Caretaker{
private MementoIF m ;
public void saveMemento(MementoIF m){
this.m = m;
}
public MementoIF getMemento(){
return m;
}
}
|
第三种方式是不太推荐使用的:使用clone方法来简化备忘录模式。由于Java提供了clone机制,这使得复制一个对象变得轻松起来。使用了
clone机制的备忘录模式,备忘录角色基本可以省略了,而且可以很好的保持对象的封装。但是在为你的类实现clone方法时要慎重啊。
在上面的教学代码中,我们简单的模拟了备忘录模式的整个流程。在实际应用中,我们往往需要保存大量“备忘发起角色”的历史状态。这时就要对我们的“备忘
录管理者角色”进行改造,最简单的方式就是采用容器来按照顺序存放备忘录角色。这样就可以很好的实现undo、redo功能了。
四、适用情况
从上面的讨论可以看出,使用了备忘录模式来实现保存对象的历史状态可以有效地保持封装边界。使用备忘录可以避免暴露一些只应由“备忘发起角色”管理却又必须存储在“备忘发起角色”之外的信息。把“备忘发起角色”内部信息对其他对象屏蔽起来, 从而保持了封装边界。
但是如果备份的“备忘发起角色”存在大量的信息或者创建、恢复操作非常频繁,则可能造成很大的开销。
GOF在《设计模式》中总结了使用备忘录模式的前提:
1) 必须保存一个对象在某一个时刻的(部分)状态, 这样以后需要时它才能恢复到先前的状态。
2) 如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
五、总结
介绍了怎样来使用备忘录模式实现存储对象历史状态的功能,并对基于Java的实现进行了讨论。欢迎大家指正。
出处:http://dev.yesky.com/450/2070450.shtml
分享到:
相关推荐
在深入浅出Java设计模式的高清中文PDF文件中,首先以一个生活化的例子引出了工厂模式的概念,介绍了工厂模式在面向对象编程中的重要性和实用性。文档详细讲解了20多种Java设计模式,并且在讲解的过程中包含了丰富的...
总的来说,深入浅出设计模式附书源码Java版源代码是一份宝贵的资源,对于想要提升Java设计能力的开发者来说,它提供了一个实践和学习设计模式的绝佳平台。通过实际操作和调试代码,你可以更好地理解和掌握这些模式,...
总结来说,《深入浅出设计模式》是一本以易懂的方式介绍设计模式的优秀教材,结合书中给出的Java代码,无论你是Java开发者还是其他语言的程序员,都能从中受益,掌握设计模式这一核心的软件工程技能。通过学习本书,...
《深入浅出设计模式》是一本旨在帮助开发者理解和应用设计模式的经典书籍,它提供了C#和JAVA两种语言的源代码实现,使得学习者可以通过实际操作来加深对设计模式的理解。 1. **设计模式的基本概念**: 设计模式...
《深入浅出设计模式》是一本专为Java开发者编写的关于设计模式的中文教材,它旨在帮助读者理解和掌握设计模式这一编程领域的核心概念。设计模式是软件开发中的经验总结,是解决常见问题的有效模板,通过将成熟的设计...
《Java设计模式》是刘伟老师的一本经典教材,它深入浅出地讲解了软件设计中的重要概念——设计模式。设计模式是经验丰富的开发者在解决常见问题时总结出的通用解决方案,是软件开发中的智慧结晶。这本书的课后习题和...
本资料"深入浅出Java 23种设计模式"旨在帮助开发者理解和应用这23种经典设计模式。 首先,我们要了解设计模式的三大类别:创建型模式、结构型模式和行为型模式。创建型模式关注对象的创建过程,如单例模式...
5.6MementoPattern(备忘录模式) 223 5.6.1定义 223 5.6.2现实示例——音响均衡器 226 5.6.3C#实例——销售目标 226 5.6.4Java实例——多次Undo(取消)操作 231 5.6.5优势和缺陷 236 5.6.6应用情景 236 5.7...
《深入浅出设计模式样章》是一本专为软件开发者准备的指南,旨在帮助读者理解和掌握设计模式这一核心编程概念。设计模式是软件工程中经过时间验证、在特定情境下解决常见问题的有效方法,它提供了可重用的解决方案,...
本电子书集合深入浅出地剖析了Java设计模式,旨在帮助开发者理解和应用这些模式,提升编程技能。 首先,让我们探讨“设计模式”的概念。设计模式并不是具体的代码或库,而是一种描述在特定编程环境中常见问题的最佳...
【备忘录模式(Memento Pattern)】是一种设计模式,主要目的是为了在不破坏对象封装性的前提下,能够保存和恢复对象的内部状态。这种模式常用于实现撤销/重做功能,例如在文本编辑器、游戏或数据库管理系统中。通过...
这本书不仅深入浅出地讲解了23种经典的设计模式,还提供了丰富的实践案例,旨在帮助读者提升软件设计的水平和代码的可维护性。 首先,我们要理解什么是设计模式。设计模式是软件工程中经过验证的、在特定情境下解决...
Java的23种设计模式是软件工程中非常重要的概念,它们是...以上是Java中23种设计模式的基本介绍,每一种模式都有其特定的适用场景,理解和熟练掌握这些设计模式,能够帮助开发者编写出更加灵活、可维护和可扩展的代码。
《Java 设计模式与原理》这本书被誉为Java程序员的必备指南之一,它深入浅出地讲解了23种经典的设计模式,并提供了详细的Java源代码示例,帮助读者更好地理解和应用这些模式。 #### 二、设计模式分类 设计模式通常...
在这个压缩包中,包含了程细柱老师的22至27章的Java设计模式电子课件,涵盖了多种经典的设计模式,如中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。接下来,我们将详细探讨...
《Head First设计模式》是一本非常受欢迎的设计模式入门书籍,其深入浅出的讲解方式使复杂概念变得易于理解。而《HeadFirst in Java》则是学习Java编程的优秀教程,它涵盖了Java的基础和高级特性,同时也融入了设计...
《Java经典设计模式》中文版是一本深入浅出地介绍设计模式的书籍,它以Head First的方式呈现,使得复杂的概念变得生动易懂。设计模式是软件工程中的宝贵经验总结,是解决常见问题的有效模板,可以帮助开发者写出更...
本资料“图解Java设计模式笔记总结word版本”聚焦于通过图文并茂的方式,深入浅出地解析各种设计模式。以下是基于这个主题的详细知识点讲解: 1. **设计模式的分类** - **创建型模式**:如单例(Singleton)、工厂...