J2EE从入门到精通28-31第三卷 设计模式

上传人:dfg****19 文档编号:172522483 上传时间:2022-12-05 格式:DOC 页数:102 大小:1.83MB
收藏 版权申诉 举报 下载
J2EE从入门到精通28-31第三卷 设计模式_第1页
第1页 / 共102页
J2EE从入门到精通28-31第三卷 设计模式_第2页
第2页 / 共102页
J2EE从入门到精通28-31第三卷 设计模式_第3页
第3页 / 共102页
资源描述:

《J2EE从入门到精通28-31第三卷 设计模式》由会员分享,可在线阅读,更多相关《J2EE从入门到精通28-31第三卷 设计模式(102页珍藏版)》请在装配图网上搜索。

1、第三卷设计模式程序设计是思维具体化的一种方式,是思考如何解决问题的过程,设计模式是在解决问题的过程中,一些良好思路的经验集成,最早讲设计模式,人们总会提到Gof的著作,它最早将经典的23种模式集合在一起说明,对后期学习程序设计,尤其是对从事对象导向程序设计的人们起了莫大的影响。后来设计模式一词被广泛的应用到各种经验集成,甚至还有反模式(AntiPattern),反模式教导您如何避开一些常犯且似是而非的程序设计思维。这边的话将整理一些设计模式学习心得,实作的部份是使用Java,因而您会看到一些与Gof模式不同的图及实作方式,这是为了善用一些Java本身的特性,至于C+的实作方面,Gof的书已经给

2、了不少的例子。在一些模式的实作上,您会发现我用了介面(interface)来取代抽象类别(Abstractclass),这与原先的Gof书中的范例会不尽相同,这是因为在C+中没有介面,一个完全没有实作任何方法的抽象类别,根据当时描述的主题特性,可以的话会将之换为介面,在语义上会较符合Java语言的特性,但是您要知道的是,介面与完全没有实作任何方法的抽象类别在某些时候是可以互换的。在这边所看到的UML图都是使用Jude绘制的,Jude是一个纯Java撰写的UML工具程序,可运行与Windows、Linux等多个平台,体积小,使用简易。Gof模式以下的设计模式则是我个人从Gof学习中的个人体会与实

3、作,并增加几个导入或衍生的简单模式。Creational模式对象的产生需要消耗系统资源,所以如何有效率的产生、管理与操作对象,一直都是值得讨论的课题,Creational模式即与对象的建立相关,在这个分类下的模式给出了一些指导原则及设计的方向。SimpleFactory模式AbstractFactory模式Builder模式FactoryMethod模式Prototype模式Singleton模式RegistryofSingleton模式Structural模式如何设计对象之间的静态结构,如何完成对象之间的继承、实现与依赖关系,这关乎着系统设计出来是否健壮(robust):像是易懂、易维护、易

4、修改、耦合度低等等议题。Structural模式正如其名,其分类下的模式给出了在不同场合下所适用的各种对象关系结构。DefaultAdapter模式Adapter模式-ObjectAdapterAdapter模式-ClassAdapterBridge模式Composite模式Decorator模式Facade模式Flyweight模式Proxy模式(一)Proxy模式(二)Behavioral模式对象之间的合作行为构成了程序最终的行为,对象之间若有设计良好的行为互动,不仅使得程序执行时更有效率,更可以让对象的职责更为清晰、整个程序的动态结构(像是对象调度)更有弹性。ChainofRespons

5、ibility模式Command模式Interpreter模式Iterator模式Mediator模式Memento模式Observer模式State模式Strategy模式TemplateMethod模式Visitor模式多执行绪模式在很多应用中都会使用多执行绪,尤其是在Web应用中,多执行绪以Gof整理的模式为基础,考量多执行绪环境中,如何组合这些基本模式来完成多执行绪安全要求。GuardedSuspension模式ProducerConsumer模式WorkerThread模式Thread-Per-Message模式Future模式Read-Write-Lock模式Two-phaseTe

6、rmination模式Thread-SpecificStorage模式参考资料以下是以Java实作设计模式的介绍网站,从下面的连结开始,当中您可以找到更多设计模式的资源。HustonDesignPatternTheDesignPatternsJavaCompanion板桥里人的Java设计模式学习心得UML软件工程组织28.Creational模式对象的产生需要消耗系统资源,所以如何有效率的产生、管理与操作对象,一直都是值得讨论的课题,Creational模式即与对象的建立相关,在这个分类下的模式给出了一些指导原则及设计的方向。28.1SimpleFactory模式SimpleFactory模

7、式(又称StaticFactory模式),一个SimpleFactory生产成品,而对客户端隐藏产品产生的细节,对象如何生成,生成前是否与其它对象建立依赖关系,客户端皆不用理会,用以将对象生成方式之变化与客户端程序码隔离。实作时定义一个产品介面(interface),并透过特定静态方法来建立成品。假设有一个音乐盒工厂,购买音乐盒的客人不用知道音乐盒是如何制作的,他只要知道如何播放音乐盒就可以了,以UML类别图来表示以上的概念:如上图所示的,MusicBoxDemo代表了客户的角色,它只依赖于IMusicBox介面,而不关心特定的实作,实际如何产生IMusicBox的实例由MusicBoxFac

8、tory完成,以一个简单的程序来实现上面这个UML类别图:IMusicBox.javapublicinterfaceIMusicBoxpublicvoidplay();PianoBox.javapublicclassPianoBoximplementsIMusicBoxpublicvoidplay()System.out.println(拨放钢琴音乐:);ViolinBox.javapublicclassViolinBoximplementsIMusicBoxpublicvoidplay()System.out.println(拨放小提琴音乐_);MusicBoxFactory.javapub

9、licclassMusicBoxFactorypublicstaticIMusicBoxcreateMusicBox(Stringname)throwsInstantiationException,IllegalAccessException,ClassNotFoundException/这边使用的是Java的Reflection机制来产生实例/不过客户端不用管啦/以后就算改变了这边的程序,客户端程序是不用更改的IMusicBoxbox=(IMusicBox)Class.forName(name).newInstance()/也许您还会作一些对box的属性设定之类的处理./.returnbox

10、;MusicBoxDemo.javapublicclassMusicBoxDemopublicstaticvoidmain(Stringargs)throwsExceptionplayMusicBox(MusicBoxFactory.createMusicBox(PianoBox);playMusicBox(MusicBoxFactory.createMusicBox(ViolinBox);publicstaticvoidplayMusicBox(IMusicBoxmusicBox)musicBox.play();由于客户端只依赖于IMusicBox介面,所以即使您日后改变了createMus

11、icBox()中的实作方式,对客户端是一点影响也没有的,白话来说,音乐盒制作方式会因技术进步而变,但不影响客户如何操作音乐盒,因为客户只要知道操作介面即可。来看看SimpleFactory的类别结构:客户只要面对Factory,客户依赖于产品介面,产品的具体实作是可以与客户隔开的,它们也是可以抽换的。将SimpleFactory的概念扩充,可以设计出各种对象皆通用的Factory类别,作为用来专门生成、组装、管理对象的容器。28.2AbstractFactory模式假设您要制作一个对话方块(Dialog)元件,您希望的是这个对话方块可以有不同的视感(Look-and-feel),最基本的想法是

12、,藉由Setter将不同视感的元件设定给这个对话方块,例如:CustomDialog.javapublicclassCustomDialogprivateIButtonbutton;privateITextFieldtextField;publicvoidsetButton(IButtonbutton)this.button=button;publicvoidsetTextField(ITextFieldtextField)this.textField=textField;publicvoidlayoutAllComponents()/.publicvoidshowDialog()this.p

13、aintDialog();button.paintButton();textField.paintTextField();publicvoidpaintDialog()System.out.println(customdialogpaints.);很简单,这是最基本的介面依赖,Setter依赖于IButton与ITextField两个介面,而不是其实作类别,不过这边还有个进一步的要求,使用上面的方式还必须亲自呼叫Setter、layout等方法,您希望视感的更换可以更简单些,例如只要透一个元件的替换就可以完成对话方块上所有元件的视感更换。您可以使用AbstractFactory模式,将所有对话

14、方块所需要的产生的元件加以封装,对话方块依赖于AbstractFactory,实际上具体的Factory实现则分别产生对话方块所需要的视感元件,下面的UML类别图展现这种概念。现在如果要更换所有的视感元件,就只要抽象掉具体的Factory就可以了,例如:CustomDialogwindowsDialog=newCustomDialog(newWindowsWidgetFactory();windowsDialog.showDialog();CustomDialogmacDialog=newCustomDialog(newMacWidgetFactory();macDialog.showDial

15、og();来将上面的UML图具体实现出来。CustomDialog.javapublicclassCustomDialogprivateIButtonbutton;privateITextFieldtextField;publicCustomDialog(IWidgetFactorywidgetFactory)setWidgetFactory(widgetFactory);/由于客户端只依赖于抽象的工厂,工厂如何实作并无关客户端的事/要抽换工厂并不需要改动客户端的程序publicvoidsetWidgetFactory(IWidgetFactorywidgetFactory)setButton

16、(widgetFactory.createButton();setTextField(widgetFactory.createTextField();/.publicvoidlayoutAllComponents()/layoutallcomponents/这边也是依赖抽象,实际改变了元件实例/客户端代码也不用更改publicvoidsetButton(IButtonbutton)this.button=button;publicvoidsetTextField(ITextFieldtextField)this.textField=textField;publicvoidshowDialog(

17、)this.paintDialog();button.paintButton();textField.paintTextField();publicvoidpaintDialog()System.out.println(customdialogpaints.);IButton.javapublicinterfaceIButtonpublicvoidpaintButton();ITextField.javapublicinterfaceITextFieldpublicvoidpaintTextField();IWidgetFactory.javapublicinterfaceIWidgetFac

18、torypublicIButtoncreateButton();publicITextFieldcreateTextField();MacButton.javapublicclassMacButtonimplementsIButtonpublicvoidpaintButton()System.out.println(Macbuttonpaints.);WindowsButton.javapublicclassWindowsButtonimplementsIButtonpublicvoidpaintButton()System.out.println(Windowsbuttonpaints.);

19、MacTextField.javapublicclassMacTextFieldimplementsITextFieldpublicvoidpaintTextField()System.out.println(MactextFieldpaints.);WindowsTextField.javapublicclassWindowsTextFieldimplementsITextFieldpublicvoidpaintTextField()System.out.println(WindowstextFieldpaints.);MacWidgetFactory.javapublicclassMacW

20、idgetFactoryimplementsIWidgetFactorypublicIButtoncreateButton()returnnewMacButton();publicITextFieldcreateTextField()returnnewMacTextField();WindowsWidgetFactory.javapublicclassWindowsWidgetFactoryimplementsIWidgetFactorypublicIButtoncreateButton()returnnewWindowsButton();publicITextFieldcreateTextF

21、ield()returnnewWindowsTextField();下图是AbstractFactory模式的UML结构图:简单的说,在AbstractFactory模式中将具体的Product封装在具体Factory实现中,而客户仍只要面对Factory与Product的抽象介面,避免依赖于具体的Factory与Product,由于Factory封装了所必须的Product,所以要更换掉所有的元件,只要简单的抽换掉Factory就可以了,不用修改客户端的程序。28.3Builder模式您想要建立一个迷宫产生程序,迷宫使用二维阵列来定义,0表示道路,1表示墙,2表示宝物,根据所定义的二维迷宫阵

22、列,您想要程序自动产生各种不同材质的迷宫,例如砖墙迷宫,钻石迷宫等等。您可以在程序中定义两个角色,一个是指导迷宫建立的Director角色,一个是按照指导者指示建立迷宫的Builder角色,Director根据定义的迷宫阵列来指导Builder,只要更换Builder,就可以完成不同材质的迷宫。可以使用下面的UML类别图来表示上述的概念:实际上的程序设计如下:MazeDirector.javapublicclassMazeDirectorprivateintmaze;privateIMazeBuildermazeBuilder;publicvoidsetMaze(intmaze)this.ma

23、ze=maze;publicvoidsetMazeBuilder(IMazeBuildermazeBuilder)this.mazeBuilder=mazeBuilder;publicvoidbuildMaze()for(inti=0;imaze.length;i+)for(intj=0;jmazei.length;j+)/由于mazeBuilder是IMazeBuilder型态/所以无论Builder实例为何,这边的程序都无需变动switch(mazeij)case0:mazeBuilder.createRoadBlock();break;case1:mazeBuilder.createWa

24、llBlock();break;case2:mazeBuilder.createTreasureBlock();break;default:System.out.println(undefined);mazeBuilder.nextRow();IMazeBuilder.javapublicinterfaceIMazeBuilderpublicvoidcreateRoadBlock();publicvoidcreateWallBlock();publicvoidcreateTreasureBlock();publicvoidnextRow();SoliderMazeBuilder.javapub

25、licclassSolidMazeBuilderimplementsIMazeBuilderpublicvoidcreateWallBlock()System.out.print();publicvoidcreateRoadBlock()System.out.print();publicvoidcreateTreasureBlock()System.out.print($);publicvoidnextRow()System.out.println();DiamondMazeBuilder.javapublicclassDiamondMazeBuilderimplementsIMazeBuil

26、derpublicvoidcreateWallBlock()System.out.print();publicvoidcreateRoadBlock()System.out.print();publicvoidcreateTreasureBlock()System.out.print(*);publicvoidnextRow()System.out.println();使用下面的程序来测试一下,它将产生两个迷宫图形:publicclassMainpublicstaticvoidmain(Stringargs)intmaze=1,1,1,1,1,1,1,1,0,0,0,0,2,1,1,0,1,0

27、,1,0,1,1,0,2,1,0,1,1,1,1,0,1,0,1,1,1,0,0,2,0,0,1,1,1,1,1,1,1,1;MazeDirectormazeDirector=newMazeDirector();mazeDirector.setMaze(maze);System.out.println(BuildSolidMaze.);mazeDirector.setMazeBuilder(newSolidMazeBuilder();mazeDirector.buildMaze();System.out.println(BuildDiamondMaze.);mazeDirector.setMa

28、zeBuilder(newDiamondMazeBuilder();mazeDirector.buildMaze();在迷宫例子中并没有产生或返回产品对象,这视您的需求而定,迷宫例子只是将结果输出至主控台,您也可以设计一个产品对象,或是将结果直接输出为文件。在Gof中有给出了一个不错的例子,以设计文件剖析器为例,该剖析器可以将文件转换为其它的格式,以DOC文件剖析器为例好了,假设希望析剖器可以将DOC文件转换为RTF或是PDF文件,可以如下设计结构:简单来说,建筑者模式适用的场合,在于使得您可以依赖抽象的建筑蓝图,而实际建造时可以使用不同的实例,这是其之所以命为Builder的原因。28.4F

29、actoryMethod模式考虑一个状况,您所经营的工厂正在生产一个新的电视机产品,现在有一个问题发生了,您的电视机产品所有的组件都可以自行生产,像是操作面版、电源、摇控装置等等等,但荧幕却必须依赖另一个厂商或子厂商供应,这时您怎么办?您不能将生产进度停下了,相反的您必须确定一些事情,您知道有关于荧幕控制的所有介面,您可以将这些对介面的操作沟通先实现,等到荧幕到了,直接将荧幕与您的半成品组合起来,一个完整的成品即可出厂。FactoryMethod模式在一个抽象类中留下某个创建元件的抽象方法没有实作,其它与元件操作相关联的方法都先依赖于元件所定义的介面,而不是依赖于元件的实现,当您的成品中有一个

30、或多个元件无法确定时,您先确定与这些元件的操作介面,然后用元件的抽象操作介面先完成其它的工作,元件的实作(实现)则推迟至实现元件介面的子类完成,一旦元件加入,即可完成您的成品。再举一个例子,假设您要完成一个文件编辑器,您希望这个编辑器可以适用于所有类型的档案编辑,例如RTF、DOC、TXT等等,尽管这些文件有着不同的格式,您先确定的是这些文件必然具备的一些操作介面,例如储存、开启、关闭等等,您用一个IDocument类型来进行操作,这么一来这个框架就无需考虑实际的储存、开启等细节是如何进行的。以UML类别图来表现以下的概念:AbstractEditor中的createDocument()方法是

31、个抽象方法,因为框架不知道您将实现一个什么类型的文件,这个抽象方法将推迟至继承AbstractEditor的子类中实现。这个架构可用以下简单的示意程序来作示范,当中实现了一个RTFDocument,虽然在AbstractEditor中并不知道我们会套用这个RTFDocument,但您可以看到,透过多型操作,您的框架可以进行对文件的相关操作。AbstractEditor.javapublicabstractclassAbstractEditorprivateIDocumentdocument;publicabstractIDocumentcreateDocument();publicvoidne

32、wDocument()document=createDocument();document.open();publicvoidsaveDocument()if(document!=null)document.save();publicvoidcloseDocument()if(document!=null)document.close();IDocument.javapublicinterfaceIDocumentpublicvoidopen();publicvoidsave();publicvoidclose();RTFEditor.javapublicclassRTFEditorexten

33、dsAbstractEditorpublicIDocumentcreateDocument()returnnewRTFDocument();RTFDocument.javapublicclassRTFDocumentimplementsIDocumentpublicRTFDocument()System.out.println(建立RTF文件);publicvoidopen()System.out.println(开启文件);publicvoidsave()System.out.println(储存文件);publicvoidclose()System.out.println(关闭文件);将F

34、actoryMethod的结构绘出如下:FactoryMethod中的AbstractOperator中拥有一个抽象的factoryMethod()方法,它负责生成一个IProduct类型的对象,由于目前还不知道将如何实现这个类型,所以将之推迟至子类别中实现,在AbstractOperator中先实现IProduct操作介面沟通的部份,只要介面统一了,利用多型操作即可完成各种不同的IProduct类型之对象操作。也就是说,对AbstractOperator来说,其操作的IProduct是可以抽换的。28.5Prototype模式您从图书馆的期刊从发现了几篇您感兴趣的文章,由于这是图书馆的书,您

35、不可以直接在书中作记号或写字,所以您将当中您所感兴趣的几个主题影印出来,这下子您就可在影印的文章上画记重点。Prototype模式的作用有些类似上面的描述,您在父类别中定义一个clone()方法,而在子类别中重新定义它,当客户端对于所产生的对象有兴趣并想加以利用,而您又不想破坏原来的对象,您可以产生一个对象的复本给它。Prototype具有展示的意味,就像是展览会上的原型车款,当您对某个车款感兴趣时,您可以购买相同款示的车,而不是车展上的车。在软体设计上的例子会更清楚的说明为何要进行对象复制,假设您要设计一个室内设计软体,软体中有一个展示家具的工具列,您只要点选工具列就可以产生一个家具复本,例

36、如一张椅子或桌子,您可以拖曳这个复制的对象至设计图中,随时改变它的位置、颜色等等,当您改变设计图中的对象时,工具列上的原型工具列是不会跟着一起改变的,这个道理是无需解释的。下面的UML类别图表示了上述的简单概念:Prototype模式的重点在于clone(),它负责复制对象本身并传回,但这个clone()本身在实作上存在一些困难,尤其是当对象本身又继承另一个对象时,如何确保复制的对象完整无误,在不同的程序语言中有不同的作法。在Java中的作法是透过实作一个Cloneable介面,它只是一个声明的介面,并无规定任何实作的方法,您的目的是改写Object的clone()方法,使其具备有复制对象的功

37、能,这个方面建议您参考:Howtoavoidtrapsandcorrectlyoverridemethodsfromjava.lang.Object。用一个简单的例子来实作上图中的结构,这个例子利用了Java语言本身的clone特性:AbstractFurniture.javapublicabstractclassAbstractFurnitureimplementsCloneablepublicabstractvoiddraw();/在DesignPattern上,以下的clone是抽象未实作的/实际上在Java中class都继承自Object/所以在这边我们直接重新定义clone()/这是

38、为了符合Java现行的clone机制protectedObjectclone()throwsCloneNotSupportedExceptionreturnsuper.clone();CircleTable与SquareTable继承了AbstractFurniture,并实作clone方法,用于传回本身的复制品:CircleTable.javaimportjava.awt.*;publicclassCircleTableextendsAbstractFurnitureprotectedPointcenter;publicvoidsetCenter(Pointcenter)this.cente

39、r=center;protectedObjectclone()throwsCloneNotSupportedExceptionObjecto=super.clone();if(this.center!=null)(CircleTable)o).center=(Point)center.clone();returno;publicvoiddraw()System.out.println(t圆桌t中心:(+center.getX()+,+center.getY()+);SquareTable.javaimportjava.awt.*;publicclassSquareTableextendsAbs

40、tractFurnitureprotectedRectanglerectangle;publicvoidsetRectangle(Rectanglerectangle)this.rectangle=rectangle;protectedObjectclone()throwsCloneNotSupportedExceptionObjecto=super.clone();if(this.rectangle!=null)(SquareTable)o).rectangle=(Rectangle)rectangle.clone();returno;publicvoiddraw()System.out.p

41、rint(t方桌t位置:(+rectangle.getX()+,+rectangle.getY()+);System.out.println(/宽高:(+rectangle.getWidth()+,+rectangle.getHeight()+);House是个虚拟的房屋对象,从Prototype复制出来的对象加入至House中:House.javaimportjava.util.*;publicclassHouseprivateVectorvector;publicHouse()vector=newVector();publicvoidaddFurniture(AbstractFurnitu

42、refurniture)vector.addElement(furniture);System.out.println(现有家具.);Enumerationenumeration=vector.elements();while(enumeration.hasMoreElements()AbstractFurnituref=(AbstractFurniture)enumeration.nextElement();f.draw();System.out.println();再来是应用程序本身:Application.javaimportjava.awt.*;publicclassApplicati

43、onprivateAbstractFurniturecircleTablePrototype;publicvoidsetCircleTablePrototype(AbstractFurniturecircleTablePrototype)this.circleTablePrototype=circleTablePrototype;publicvoidrunAppExample()throwsExceptionHousehouse=newHouse();CircleTablecircleTable=null;/从工具列选择一个家具加入房子中circleTable=(CircleTable)cir

44、cleTablePrototype.clone();circleTable.setCenter(newPoint(10,10);house.addFurniture(circleTable);/从工具列选择一个家具加入房子中circleTable=(CircleTable)circleTablePrototype.clone();circleTable.setCenter(newPoint(20,30);house.addFurniture(circleTable);publicstaticvoidmain(Stringargs)throwsExceptionApplicationapplic

45、ation=newApplication();application.setCircleTablePrototype(newCircleTable();application.runAppExample();Java中的clone()方法是继承自Object,AbstractFurniture的子类别则override这个clone()方法,以复制其本身并传回。下图为Prototype模式的类别结构图:在Gof的设计模式书中给出一个原型模式的应用:一个通用的图型编辑器Framework。在这个Framework中有一个工具列,您可以在上面选择音乐符号以加入乐谱中,并可以随时调整音乐符号的位置等

46、等。图型编辑器Framework是通用的,然而它并不知道这些音乐符号的型态,有人或许会想到继承图型编辑器Framework来为每个音乐符号设计一个框架子类别,但由于音乐符号的种类很多,这会产生相当多的子类别,为了避免这种情况,可以透过Prototype模式来减少子类别的数目,可以设计出以下的结构:依照这个结构,图型编辑器的Framework可以独立于要套用的特定类别之外,虽然不知道被复制传回的对象型态是什么,但总可以按照Graphics所定义的介面来操作这些对象。28.6Singleton模式Singleton的英文意义是独身,也就是只有一个人,应用在对象导向语言上,通常翻译作单例:单一个实例

47、(Instance)。很多时候,您会需要Singleton模式,例如印表机管理,您希望程序中只能有一个PrintSpooler,以避免两个列印动作同时输入至印表机中;例如资料库管理,因为建立连接(Connection)对象会耗用资源,您希望程序中只能有一个连接对象,所有其它的程序都透过这个对象来连接资料库,以避免连接对象的重复开启造成资源的耗用;例如系统程序属性档的读取,您使用单一个对象来读取属性内容,而程序的其它部份都向这个对象要求属性资料,而不是自行读取属性资料。以印表机设计为例,有的设计人员会采取全域变数的方式来建立实例,并在程序中随机取用这个实例,Java虽然不支援全域变数,但透过将对

48、象包装在一个类别之中,也有人会采用这样的写法:publicclassPrintSpoolerpublicPrintSpooler()/.publicConnectiongetSpooler().publicclassGlobalObjectprivatePrintSpoolerprintSpooler;publicGlobalObject()printSpooler=newPrintSpooler();.publicvoidgetPrintSpooler()returnprintSpooler;无论全域变数或是以上的例子,都无法保证只产生唯一个实例,您也许会注意不犯这个错误,但与您共同工作的伙

49、伴也许会直觉的使用建构方法来产生一个PrintSpooler实例。Singleton模式可以保证一个类别只有一个实例,并提供一个访问(visit)这个实例的方法。一个Singleton实作即为Java中的java.lang.Runtime类别,每个Java程序执行时都有一个唯一的Runtime对象,可以透过它提供的静态方法getRuntime()方法来取得这个对象,例如:Runtimeruntime=Runtime.getRuntime();取得Runtime对象之后,您可以透过它进行一些外部命令的执行、进行垃圾处理等等指令,您可以开启Runtime.java类别,开头的几行是这样写的:pub

50、licclassRuntimeprivatestaticRuntimecurrentRuntime=newRuntime();publicstaticRuntimegetRuntime()returncurrentRuntime;/*Dontletanyoneelseinstantiatethisclass*/privateRuntime()/以下略上面结构即采用Singleton模式设计,其结构使用UML来表即如下所示:如上所示的,Java使用静态工厂来取得Runtime对象,其中Runtime的建构函式被宣告为private,这样可以阻止其他人使用建构方法来建立实例;使用更一般化的表示单例

51、的UML结构,如下图所示:有几个实作上面结构的方法,可以在第一次需要实例时再建立对象,也就是采用所谓的LazyInitialization:publicclassSingletonprivatestaticSingletoninstance=null;privateSingleton()/.publicstaticSingletongetInstance()if(instance=null)instance=newSingleton();returninstance;/.其它实作上面的实作适用于单执行绪的程序,在多执行绪的程序下,以下的写法在多个执行绪的竞争资源下,将仍有可能产生两个以上的实例

52、,例如下面的情况:Thread1:if(instance=null)/trueThread2:if(instance=null)/trueThread1:instance=newSingleton();/产生一个实例Thread2:instance=newSingleton();/又产生一个实例Thread1:returninstance;/回传一个实例Thread2:returninstance;/又回传一个实例在多执行绪的环境下,为了避免资源同时竞争而导致如上产生多个实例的情况,加上同步(synchronized)机制:publicclassSingletonprivatestaticSi

53、ngletoninstance=null;privateSingleton()synchronizedstaticpublicSingletongetInstance()if(instance=null)instance=newSingleton();returninstance;不过这种简单的写法不适合用于像伺服器这种服务很多执行绪的程序上,同步机制会造成相当的效能低落,为了顾及Singleton、LazyInitialization与效能问题,因而有了Double-checkLocking的模式:publicclassSingletonprivatestaticSingletoninsta

54、nce=null;privateSingleton()publicstaticSingletongetInstance()if(instance=null)synchronized(Singleton.class)if(instance=null)instance=newSingleton();returninstance;Java中Runtime类别的作法就简单多了,它舍弃了LazyInitialization,如果您的实例初始化不是很久的话,可以用这种方式:publicclassSingletonprivatestaticSingletoninstance=newSingleton();p

55、rivateSingleton()/.publicstaticSingletongetInstance()returninstance;/其它实作Singleton本身的观念简单但应用很广,因而很多时候必须对实际环境作一些考量与调整,建议您也看看有关于Singleton的这篇讨论。28.7RegistryofSingleton模式考虑使用Singleton模式时拥有子类别的问题,在Singleton模式中的getInstance()通常是一个静态方法,不能在子类别中重新定义它,关于子类别实例的产生交由getInstance()来进行是最好的选择,例如:publicclassSingletonp

56、rivatestaticSingletoninstance=null;privateSingleton()/.publicstaticSingletongetInstance()if(instance=null)/getEnv表示系统环境变数Stringstyle=getEnv(style);if(style.equals(child1)instance=newChildSingleton1();elseif(style.equals(child2r)instance=newChildSingleton2();elseinstance=newSingleton();return_instanc

57、e;/.上面这个程序片段改写自Gof书中关于Singleton的例子,并用Java实现;在书中指出,这个例子的缺点是每增加一个子类别,getInstance()就必须重新修改,这个问题在Java中可以使用Reflection机制来解决:publicclassSingletonprivatestaticSingletoninstance=null;privateSingleton()/.publicstaticSingletongetInstance()if(instance=null)/getEnv表示环境变数Stringstyle=getEnv(style);tryinstance=(Sin

58、gleton)Class.forName(style).newInstance();catch(Exceptione)System.out.println(Sorry!Nosuchclassdefined!);returninstance;/.上面的方式使用了Java的Reflection机制,并透过环境变数设定要产生的子类Singleton,如果不使用Reflection的话,Gof书中提出的改进方法是使用RegistryofSingleton方法:importjava.util.*;publicclassSingleton/注册表,用于注册子类别对象privatestaticMapregi

59、stry=newHashMap();privatestaticSingletoninstance;publicstaticvoidregister(Stringname,Singletonsingleton)registry.put(name,singleton);publicstaticSingletongetInstance()if(instance=null)/getEnv表示取得环境变数Stringstyle=getEnv(style);instance=lookup(style);returninstance;protectedstaticSingletonlookup(Stringname)return(Singleton)registry.get(name);在Gof书中使用List来实现注册表,而在这边使用HasMap类别来实现,它是由JavaSE所提供的;在父类别中提供一个register()以注册Singleton的子类别所产生之实例,而注册的时机可以放在子类别的建构方法中加以实现,例如:publicclassChildSingleton1extendsSingletonpublicChildSingleton1()/./注册子类别对

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!