设计模式问题_第1页
设计模式问题_第2页
设计模式问题_第3页
设计模式问题_第4页
设计模式问题_第5页
已阅读5页,还剩34页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

设计模式遵循的原则有6个:1、开闭原则(OpenClosePrinciple)对扩展开放,对修改关闭。2、 里氏代换原则(LiskovSubstitutionPrinciple)只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。3、 依赖倒转原贝U(DependenceInversionPrinciple)这个是开闭原则的基础,对接口编程,依赖于抽象而不依赖于具体。4、 接口隔离原则(InterfaceSegregationPrinciple)使用多个隔离的借口来降低耦合度。5、迪米特法则(最少知道原则)(DemeterPrinciple)一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。6、 合成复用原则(CompositeReusePrinciple)原则是尽量使用合成/聚合的方式,而不是使用继承。继承实际上破坏了类的封装性,超类的方法可能会被子类修改Num1:单例模式单例模式的关键有两点:1、 构造方法为私有,这样外界就不能随意调用。2、 get的方法为静态,由类直接调用多例模式(Multiton)1、 多例类可以有多个实例2、 多例类必须能够自我创建并管理自己的实例,并向外界提供自己的实例。一、单例模式和多例模式说明:单例模式和多例模式属于对象模式。单例模式的对象在整个系统中只有一份,多例模式可以有多个实例。它们都不对外提供构造方法,即构造方法都为私有。单例和多例的详细描述:1.什么是单例多例:所谓单例就是所有的请求都用一个对象来处理,比如我们常用的service和dao层的对象通常都是单例的,而多例则指每个请求用一个新的对象来处理,比如action;

如何产生单例多例:在通用的SSH中,单例在spring中是默认的,如果要产生多例,则在配置文件的bean中添力口scope=”prototype”;为什么用单例多例:之所以用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存;之所以用多例,是为了防止并发问题;即一个请求改变了对象的状态,此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理;用单例和多例的标准只有一个:当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),则多例,否则单例;何时用单例?何时用多例?对于struts2来说,action必须用多例,因为action本身含有请求参数的值,即可改变的状态;而对于STRUTS1来说,action则可用单例,因为请求参数的值是放在actionForm中,而非action中的;另外要说一下,并不是说service或dao一定是单例,标准同第3点所讲的,就曾见过有的service中也包含了可改变的状态,同时执行方法也依赖该状态,但一样用的单例,这样就会出现隐藏的BUG,而并发的BUG通常很难重现和查找;单例的写法第一种(懒汉,线程不安全):publicclassSingleton{privatestaticSingletoninstanee;privateSingleton(){}publicstaticSingletongetInstance(){if(instanee==null){instanee=newSingleton();}returninstanee;}}这种写法lazyloading很明显,但是致命的是在多线程不能正常工作。第二种(懒汉,线程安全):publicclassSingleton{privatestaticSingletoninstanee;

privateSingleton(){}publicstaticsynchronizedSingletongetInstance(){if(instanee==null){instanee=newSingleton();}returninstanee;}}这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazyloading,但是,遗憾的是,效率很低,99%情况下不需要同步。第三种(饿汉):publicclassSingleton{privatestaticSingletoninstanee=newSingleton();privateSingleton(){}publicstaticSingletongetInstance(){returninstanee;}}这种方式基于classloder机制避免了多线程的同步问题,不过,instanee在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getlnstanee方法,但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instanee显然没有达到lazyloading的效果。第四种(饿汉,变种):publicclassSingleton{privateSingletoninstanee=null;static{instanee=newSingleton();}privateSingleton(){}publicstaticSingletongetInstance(){returnthis.instanee;

}表面上看起来差别挺大,其实更第三种方式差不多,都是在类初始化即实例化instanee。第五种(静态内部类):publicclassSingleton{privatestaticclassSingletonHolder{privatestaticfinalSingletonINSTANCE=newSingleton();}privateSingleton(){}publicstaticfinalSingletongetInstance(){returnSingletonHolder.INSTANCE;}}这种方式同样利用了classloder的机制来保证初始化instanee时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方式是只要Singleton类被装载了,那么instanee就会被实例化(没有达到lazyloading效果),而这种方式是Singleton类被装载了,instanee不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getlnstanee方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instanee很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instanee显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理。Num2:工厂模式基本概念:为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。分为三类:•简单工厂模式SimpleFactory:不利于产生系列产品;•工厂方法模式FactoryMethod:又称为多形性工厂;•抽象工厂模式AbstractFactory:又称为工具箱,产生产品族,但不利于产生新的产品;这三种模式从上到下逐步抽象,并且更具一般性。GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(FactoryMethod)与抽象工厂模式(AbstractFactory)。将简单工厂模式(SimpleFactory)看为工厂方法模式的一种特例,两者归为一类。简单工厂模式

简单工厂模式又称静态工厂方法模式。重命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。在简单工厂模式中,一个工厂类处于对产品类实例化调用的中心位置上,它决定那一个产品类应当被实例化,如同一个交通警察站在来往的车辆流中,决定放行那一个方向的车辆向那一个方向流动一样。先来看看它的组成:工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑。在java中它往往由一个具体类实现。抽象产品角色:它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。示例代码:publicclassFactory{//getClass产生Sample一般可使用动态类装载装入类。publicstaticSamplecreator(intwhich){if(which==1)returnnewSampleA();elseif(which==2)returnnewSampleB();}}还有一种目前比较流行的规范是把静态工厂方法命名为valueOf或者getInstance。valueOf:该方法返回的实例与它的参数具有同样的值,例如:Integera=Integer.valueOf(lOO);//返回取值为100的Integer对象publicclassComplex{privatefinalfloatre;privatefinalfloatim;privateComplex(floatre,floatim){this.re=re;

this.im=im;publicstaticComplexvalueOf(floatre,floatim){returnnewComplex(re,im);}publicstaticComplexvalueOfPolar(floatr,floattheta){returnnewComplex((float)(r*Math.cos(theta)),(float)(r*Math.sin(theta)));}}从上面代码可以看出,valueOf()方法能执行类型转换操作,在本例中,把int类型的基本数据转换为Integer对象。getInstance:返回的实例与参数匹配,例如:Calendarcal二Calendar.getInstance(Locale.CHINA);//返回符合中国标准的日历工厂方法模式工厂方法模式是简单工厂模式的进一步抽象化和推广,工厂方法模式里不再只由一个工厂类决定那一个产品类应当被实例化,这个决定被交给抽象工厂的子类去做。来看下它的组成:抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的''上帝类〃。正如上面所说,这样便分担了对象承受的压力;而且这样使得结构变得灵活起来一一当有新的产品(即暴发户的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码。可以看出工厂角色的结构也是符合开闭原则的!示例代码:

//抽象产品角色publicinterfaceMoveable{voidrun();}//具体产品角色publicclassPlaneimplementsMoveable{@Overridepublicvoidrun(){System.out.println("plane....");}}//具体产品角色publicclassBroomimplementsMoveable{@Overridepublicvoidrun(){System.out.println("broom ");}}//抽象工厂publicabstractclassVehicleFactory{abstractMoveablecreate();}//具体工厂

publicclassPlaneFactoryextendsVehicleFactory{publicMoveablecreate(){returnnewPlane();}}//具体工厂publicclassBroomFactoryextendsVehicleFactory{publicMoveablecreate(){returnnewBroom();}}//测试类publicclassTest{publicstaticvoidmain(String[]args){VehicleFactoryfactory=newBroomFactory();Moveablem=factory.create();m.run();}}可以看出工厂方法的加入,使得对象的数量成倍增长。当产品种类非常多时,会出现大量的与之对应的工厂对象,这不是我们所希望的。因为如果不能避免这种情况,可以考虑使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实现。简单工厂和工厂方法模式的比较工厂方法模式和简单工厂模式在定义上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式,把核心放在一个实类上。工厂方法模式可以允许很多实的工厂类从抽象工厂类继承下来,从而可以在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模

式。反过来讲,简单工厂模式是由工厂方法模式退化而来。设想如果我们非常确定一个系统只需要一个实的工厂类,那么就不妨把抽象工厂类合并到实的工厂类中去。而这样一来,我们就退化到简单工厂模式了。抽象工厂模式示例代码://抽象工厂类publicabstractclassAbstractFactory{publicabstractVehiclecreateVehicle();publicabstractWeaponcreateWeapon();publicabstractFoodcreateFood();}//具体工厂类,其中Food,Vehicle,Weapon是抽象类,publicclassDefaultFactoryextendsAbstractFactory{@OverridepublicFoodcreateFood(){returnnewApple();}@OverridepublicVehiclecreateVehicle(){returnnewCar();}@OverridepublicWeaponcreateWeapon(){returnnewAK47();

//测试类publicclassTest{publicstaticvoidmain(String[]args){AbstractFactoryf=newDefaultFactory();Vehiclev=f.createVehicle();run();Weaponw=f.createWeapon();w. shoot();Fooda=f.createFood();a.printName();}}在抽象工厂模式中,抽象产品(Abstractproduct)可能是一个或多个,从而构成一个或多个产品族(ProductFamily)。在只有一个产品族的情况下,抽象工厂模式实际上退化到工厂方法模式。总结简单工厂模式是由一个具体的类去创建其他类的实例,父类是相同的,父类是具体的。工厂方法模式是有一个抽象的父类定义公共接口,子类负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类中完成。抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。它针对的是有多个产品的等级结构。而工厂方法模式针对的是一个产品的等级结构。Num3:建造(Builder)模式基本概念:是一种对象构建的设计模式,它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。Builder模式是一步一步创建一个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容就可以构建它们。用户不知道内部的具体构建细节。Builder模式是非常类似抽象工厂模式,细微的区别大概只有在反复使用中才能体会到。

•Builder:为创建一个Product对象的各个部件指定抽象接口。ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,提供一个检索产品的接口Director:构造一个使用Builder接口的对象。Product:表示被构造的复杂对象。ConcreateBuilder创建该产品的内部表示并定义它的装配过程。为何使用是为了将构建复杂对象的过程和它的部件解耦。注意:是解耦过程和部件。因为一个复杂的对象,不但有很多大量组成部分,如汽车,有很多部件:车轮、方向盘、发动机,还有各种小零件等等,部件很多,但远不止这些,如何将这些部件装配成一辆汽车,这个装配过程也很复杂(需要很好的组装技术),Builder模式就是为了将部件和组装过程分开。如何使用首先假设一个复杂对象是由多个部件组成的,Builder模式是把复杂对象的创建和部件的创建分别开来,分别用Builder类和Director类来表示。首先,需要一个接口,它定义如何创建复杂对象的各个部件:publicinterfaceBuilder{//创建部件A 比如创建汽车车轮voidbuildPartA();

//创建部件B比如创建汽车方向盘voidbuildPartB();//创建部件C比如创建汽车发动机voidbuildPartC();//返回最后组装成品结果(返回最后装配好的汽车)//成品的组装过程不在这里进行,而是转移到下面的Director类中进行.//从而实现了解耦过程和部件ProductgetResult();}用Director构建最后的复杂对象,而在上面Builder接口中封装的是如何创建一个个部件(复杂对象是由这些部件组成的),也就是说Director的内容是如何将部件最后组装成成品:publicclassDirector{privateBuilderbuilder;publicDirector(Builderbuilder){this.builder=builder;}//将部件partApartBpartC最后组成复杂对象//这里是将车轮方向盘和发动机组装成汽车的过程publicvoidconstruet(){builder.buildPartA();builder.buildPartB();builder.buildPartC();}}Builder的具体实现ConcreteBuilder:•通过具体完成接口Builder来构建或装配产品的部件;定义并明确它所要创建的是什么具体东西;

提供一个可以重新获取产品的接口。publicclassConcreteBuilderimplementsBuilder{PartpartA,partB,partC;publicvoidbuildPartA(){//这里是具体如何构建}publicvoidbuildPartB(){//这里是具体如何构建}publicvoidbuildPartC(){//这里是具体如何构建}publicProductgetResult(){//返回最后组装成品结果}}复杂对象:产品Product:publicinterfaceProduct{}复杂对象的部件:publicinterfacePart{}我们看看如何调用Builder模式:ConcreteBuilderbuilder=newConcreteBuilder();Directordirector=newDirector(builder);director.construet();Productproduct二builder.getResult();

Builder模式的应用在Java实际使用中,我们经常用到"池"(Pool)的概念,当资源提供者无法提供足够的资源,并且这些资源需要被很多用户反复共享时,就需要使用池。"池"实际是一段内存,当池中有一些复杂的资源的"断肢"(比如数据库的连接池,也许有时一个连接会中断),如果循环再利用这些"断肢",将提高内存使用效率,提高池的性能。修改Builder模式中Director类使之能诊断"断肢"断在哪个部件上,再修复这个部件。Num4:观察者模式基本概念:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。观察者模式又叫发布-订阅(Publish/Subscribe)模式。UML结构图上图是Observer模式的结构图,让我们可以进行更方便的描述:Subject类:它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察着。抽象主题提供一个接口,可以增加和删除观察着对象。Observer类:抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。

•ConcreteSubject类:具体主题,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。•ConcreteObserver类:具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如何使用例如:老师有电话号码,学生需要知道老师的电话号码以便于在合适的时候拨打,在这样的组合中,老师就是一个被观察者(Subject),学生就是需要知道信息的观察者,当老师的电话号码发生改变时,学生得到通知,并更新相应的电话记录。先创建一个Subject类:/**Subject(目标,Subject):*目标知道它的观察者。可以有任意多个观察者观察同一个目标。*提供注册和删除观察者对象的接口。*/publicinterfaceSubject{publicvoidattach(ObservermObserver);publicvoiddetach(ObservermObserver);publicvoidnotice();}创建Observer类:/**Observer(观察者,Observer):*为那些在目标发生改变时需要获得通知的对象定义一个更新接口。*/publicinterfaceObserver{publicvoidupdate();}创建ConcreteSubject类:/**ConcreteSubject(具体目标,Teacher)*将有关状态存入各ConcreteObserve对象。

*当他的状态发生改变时,向他的各个观察者发出通知。*/publicclassTeacherimplementsSubject{privateStringphone;privateVectorstudents;publicTeacher(){phone= ;students=newVector();}@Overridepublicvoidattach(ObservermObserver){students.add(mObserver);}@Overridepublicvoiddetach(ObservermObserver){students.remove(mObserver);}@Overridepublicvoidnotice(){for(inti=0;i<students.size();i++){((Observer)students.get(i)).update();

publicStringgetPhone(){returnphone;}publicvoidsetPhone(Stringphone){this.phone=phone;notice();}}创建ConcreteObserver类:/***ConcreteObserver(具体观察者,Student):*维护一个指向ConcreteSubject对象的引用。*存储有关状态,这些状态应与目标的状态保持一致。*实现Observer的更新接口以使自身状态与目标的状态保持一致。*/publicclassStudentimplementsObserver{privateStringname;privateStringphone;privateTeachermTeacher;publicStudent(Stringname,Teachert){t=name;mTeacher=t;}publicvoidshow(){

System.out.println("Name:"+name+"\nTeacher'sphone:"+phone);@0verridepublicvoidupdate(){phone=mTeacher.getPhone();}}客户端测试:/***观察者(Observer)模式测试类*/publicclassObserverClient{publicstaticvoidmain(String[]args){Vectorstudents=newVector();Teachert二newTeacher();for(inti二0;i<10;i++){Studentst二newStudent("Andy.Chen"+i,t);students.add(st);t.attach(st);}System.out.println("WelcometoAndy.ChenBlog!"+"\n"+"ObserverPatterns."+"\n"t.setPhone("12345678");

for(inti=0;i<3;i++)((Student)students.get(i)).show()t.setPhone("87654321");for(inti=0;i<3;i++)((Student)students.get(i)).show();}}程序运行结果如下:WelcometoAndy.ChenBlog!ObserverPatterns.Name:Andy.ChenOTeacher'sphone:12345678Name:Andy.Chen1Teacher'sphone:12345678Name:Andy.Chen2Teacher'sphone:12345678Name:Andy.ChenOTeacher'sphone:87654321Name:Andy.Chen1Teacher'sphone:87654321Name:Andy.Chen2Teacher'sphone:87654321总结观察者模式何时适用?当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中可以使他们各自独立地改变和复用。

•当对一个对象的改变需要同时改变其它对象,而不知道具体由多少对象有待改变。•当一个对象必须通知其他对象,而它又不能假定其他对象是谁,换言之,你不希望这些对象是紧密耦合的。让耦合的双方都依赖于抽象,而不是依赖于具体。Num5:适配器(Adapter)模式基本概念:适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。适配器模式的用途用电器做例子,笔记本电脑的插头一般都是三相的,即除了阳极、阴极外,还有一个地极。而有些地方的电源插座却只有两极,没有地极。电源插座与笔记本电脑的电源插头不匹配使得笔记本电脑无法使用。这时候一个三相到两相的转换器(适配器)就能解决此问题,而这正像是本模式所做的事情。适配器模式的结构适配器模式有类的适配器模式和对象的适配器模式两种不同的形式。类适配器模式:在上图中可以看出,Adaptee类并没有sampleOperation2()方法,而客户端则期待这个方法。为使客户端能够使用Adaptee类,提供一个中间环节,即类Adapter,把Adaptee的API与Target类的API衔接起来。Adapter与Adaptee是继承关系,这决定了这个适配器模式是类的:•目标(Target)角色:这就是所期待得到的接口。注意:由于这里讨论的是类适配器模式,因此目标不可以是类。源(Adapee)角色:现在需要适配的接口。适配器(Adaper)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。

示例代码:publicinterfaceTarget{/***这是源类Adaptee也有的方法*/publicvoidsampleOperationl();/***这是源类Adapteee没有的方法*/publicvoidsampleOperation2();}上面给出的是目标角色的源代码,这个角色是以一个Java接口的形式实现的。可以看出,这个接口声明了两个方法:sampleOperation1()和sampleOperation2()。而源角色Adaptee是一个具体类,它有一个sampleOperation1()方法,但是没有sampleOperation2()方法。publicclassAdaptee{publicvoidsampleOperation1(){}}适配器角色Adapter扩展了Adaptee,同时又实现了目标(Target)接口。由于Adaptee没有提供sampleOperation2()方法,而目标接口又要求这个方法,因此适配器角色Adapter实现了这个方法。publicclassAdapterextendsAdapteeimplementsTarget{/***由于源类Adaptee没有方法sampleOperation2()*因此适配器补充上这个方法*/@OverridepublicvoidsampleOperation2(){//写相关的代码

}对象适配器模式:从上图可以看出,Adaptee类并没有sampleOperation2()方法,而客户端则期待这个方法。为使客户端能够使用Adaptee类,需要提供一个包装(Wrapper)类Adapter。这个包装类包装了一个Adaptee的实例,从而此包装类能够把Adaptee的API与Target类的API衔接起来。Adapter与Adaptee是委派关系,这决定了适配器模式是对象的。示例代码:publicinterfaceTarget{/***这是源类Adaptee也有的方法*/publicvoidsampleOperationl();/***这是源类Adapteee没有的方法*/publicvoidsampleOperation2();

publicclassAdaptee{publicvoidsampleOperation1(){}}适配器类:publicclassAdapter{privateAdapteeadaptee;publicAdapter(Adapteeadaptee){this.adaptee=adaptee;}/**源类Adaptee有方法sampleOperationl*因此适配器类直接委派即可*/publicvoidsampleOperation1(){this.adaptee.sampleOperationl();}/**源类Adaptee没有方法sampleOperation2*因此由适配器类需要补充此方法*/publicvoidsampleOperation2(){//写相关的代码}}类适配器和对象适配器的权衡类适配器使用对象继承的方式,是静态的定义方式;而对象适配器使用对象组合的方式,是动态组合的方式。

•对于类适配器由于适配器直接继承了Adaptee,使得适配器不能和Adaptee的子类一起工作,因为继承是静态的关系,当适配器继承了Adaptee后,就不可能再去处理Adaptee的子类了。•对于对象适配器一个适配器可以把多种不同的源适配到同一个目标。换言之,同一个适配器可以把源类和它的子类都适配到目标接口。因为对象适配器采用的是对象组合的关系,只要对象类型正确,是不是子类都无所谓。•对于类适配器适配器可以重定义Adaptee的部分行为,相当于子类覆盖父类的部分实现方法。•对于对象适配器要重定义Adaptee的行为比较困难,这种情况下,需要定义Adaptee的子类来实现重定义,然后让适配器组合子类。虽然重定义Adaptee的行为比较困难,但是想要增加一些新的行为则方便的很,而且新增加的行为可同时适用于所有的源。•对于类适配器,仅仅引入了一个对象,并不需要额外的引用来间接得到Adapteeo•对于对象适配器,需要额外的引用来间接得到Adapteeo建议尽量使用对象适配器的实现方式,多用合成或聚合、少用继承。当然,具体问题具体分析,根据需要来选用实现方式,最适合的才是最好的。适配器模式的优点•更好的复用性:系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。•更好的扩展性:在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。适配器模式的缺点过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。Num6:代理模式基本概念:为其他对象提供一种代理以控制对这个对象的访问。也可以说,在出发点到目的地之间有一道中间层,意为代理。为什么要使用•授权机制不同级别的用户对同一对象拥有不同的访问权利,如在论坛系统中,就使用proxy进行授权机制控制,访问论坛有两种人:注册用户和游客(未注册用户),论坛就通过类似ForumProxy这样的代理来控制这两种用户对论坛的访问权限。•某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动。举例两个具体情况:•如果那个对象是一个是很大的图片,需要花费很长时间才能显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很迅速,不能等待大图片处理完成,这时需要做个图片Proxy来代替真正的图片。

如果那个对象在Internet的某个远端服务器上,直接操作这个对象因为网络速度原因可能比较慢,那我们可以先用Proxy来代替那个对象。总之原则是,对于开销很大的对象,只有在使用它时才创建,这个原则可以为我们节省很多宝贵的Java内存。所以,有些人认为Java耗费资源内存,我以为这和程序编制思路也有一定的关系。如何使用以论坛系统为例,访问论坛系统的用户有多种类型:注册普通用户、论坛管理者、系统管理者、游客。注册普通用户才能发言,论坛管理者可以管理他被授权的论坛,系统管理者可以管理所有事务等,这些权限划分和管理是使用Proxy完成的。在Forum中陈列了有关论坛操作的主要行为,如论坛名称,论坛描述的获取和修改,帖子发表删除编辑等,在ForumPermissions中定义了各种级别权限的用户:publicclassForumPermissionsimplementsCacheable{/**Permissiontoreadobject.*/publicstaticfinalintREAD=0;/**Permissiontoadministertheentiresytem.*/publicstaticfinalintSYSTEM_ADMIN=1;/**Permissiontoadministeraparticularforum.*/publicstaticfinalintFORUM_ADMIN=2;/**Permissiontoadministeraparticularuser.*/publicstaticfinalintUSER_ADMIN=3;/***Permissiontoadministeraparticulargroup.

*/publicstaticfinalintGROUP_ADMIN=4;/**Permissiontomoderatethreads.*/publicstaticfinalintMODERATE_THREADS=5;/**Permissiontocreateanewthread.*/publicstaticfinalintCREATE_THREAD=6;/**Permissiontocreateanewmessage.*/publicstaticfinalintCREATE_MESSAGE=7;/**Permissiontomoderatemessages.*/publicstaticfinalintMODERATE_MESSAGES=8;publicbooleanisSystemOrForumAdmin(){return(values[FORUM_ADMIN]||values[SYSTEM_ADMIN]);}//相关操作代码}因此,Forum中各种操作权限是和ForumPermissions定义的用户级别有关系的,作为接口Forum的实现:ForumProxy正是将这种对应关系联系起来。比如,修改Forum的名称,只有论坛管理者或系统管理者可以修改,代码如下:privateForumPermissionspermissions;privateForumforum;this.authorization二authorization;publicForumProxy(Forumforum,Authorizationauthorization,ForumPermissionspermissions){this.forum=forum;this.authorization二authorization;this.permissions=permissions;}publicvoidsetName(Stringname)throwsUnauthorizedException,ForumAlreadyExistsException{//只有是系统或论坛管理者才可以修改名称if(permissions.isSystemOrForumAdmin()){forum.setName(name);}else{thrownewUnauthorizedException();}}}而DbForum才是接口Forum的真正实现,以修改论坛名称为例:

publicvoidsetName(Stringname)throwsForumAlreadyExistsExceptiont=name;//这里真正将新名称保存到数据库中saveToDb();}凡是涉及到对论坛名称修改这一事件,其他程序都首先得和ForumProxy打交道,由ForumProxy决定是否有权限做某一样事情,ForumProxy是个名副其实的"网关","安全代理系统"。在平时应用中,无可避免总要涉及到系统的授权或安全体系,不管你有无意识的使用Proxy,实际你已经在使用Proxy了。流程图Num7:装饰模式基本概念:装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。UML结构图

Component是定义一个对象接口,可以给这些对象动态地添加职责。ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责。Decorator是装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Comp

温馨提示

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

评论

0/150

提交评论