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

下载本文档

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

文档简介

设计模式有哪几种单例模式中如何实现并发的懒汉模式最简单的实现首先,能够想到的最简单的实现是,把类的构造函数写成private的,从而保证别的类不能实例化此类,然后在类中提供一个静态的实例并能够返回给使用者。这样,使用者就可以通过这个引用使用到这个类的实例了。publicclassSingletonClass{privatestaticfinalSingletonClassinstanee=newSingletonClass();publicstaticSingletonClassgetInstance(){returninstanee;}privateSingletonClass(){}}如上例,外部使用者如果需要使用SingletonClass的实例,只能通过getInstance()方法,并且它的构造方法是private的,这样就保证了只能有一个对象存在。性能优化 lazyloaded上面的代码虽然简单,但是有一个问题一一无论这个类是否被使用,都会创建一个instance对象。如果这个创建过程很耗时,比如需要连接10000次数据库(夸张了…:-)),并且这个类还并不一定会被使用,那么这个创建过程就是无用的。怎么办呢?为了解决这个问题,我们想到了新的解决方案:publicclassSingletonClass{privatestaticSingletonClassinstanee=null;publicstaticSingletonClassgetInstance(){if(instanee==null){instanee=newSingletonClass();}returninstanee;}privateSingletonClass(){}}代码的变化有两处首先,把instance初始化为null,直到第一次使用的时候通过判断是否为null来创建对象。因为创建过程不在声明处,所以那个final的修饰必须去掉。我们来想象一下这个过程。要使用SingletonClass,调用getinstance()方法。第一次的时候发现instance是null,然后就新建一个对象,返回出去;第二次再使用的时候,因为这个instance是static的,所以已经不是null了,因此不会再创建对象,直接将其返回。这个过程就成为lazyloaded,也就是迟加载 直到使用的时候才进行加载。同步上面的代码很清楚,也很简单。然而就像那句名言:“80%的错误都是由20%代码优化引起的”。单线程下,这段代码没有什么问题,可是如果是多线程,麻烦就来了。我们来分析一下:线程A希望使用SingletonClass,调用getInstance()方法。因为是第一次调用,A就发现instance是null的,于是它开始创建实例,就在这个时候,CPU发生时间片切换,线程B开始执行,它要使用SingletonClass,调用getInstance()方法,同样检测到instance是null注意,这是在A检测完之后切换的,也就是说A并没有来得及创建对象——因此B开始创建。B创建完成后,切换到A继续执行,因为它已经检测完了,所以A不会再检测一遍,它会直接创建对象。这样,线程A和B各自拥有一个SingletonClass的对象 单例失败!解决的方法也很简单,那就是加锁:publicclassSingletonClass{privatestaticSingletonClassinstanee=null;publicsynchronizedstaticSingletonClassgetInstance(){if(instanee==null){instanee=newSingletonClass();}returninstanee;}privateSingletonClass(){}}是要getInstance()加上同步锁,一个线程必须等待另外一个线程创建完成后才能使用这个方法,这就保证了单例的唯一性。又是性能上面的代码又是很清楚很简单的,然而,简单的东西往往不够理想。这段代码毫无疑问存在性能的问题 synchronized修饰的同步块可是要比一般的代码段慢上几倍的!如果存在很多次getInstance()的调用,那性能问题就不得不考虑了!让我们来分析一下,究竟是整个方法都必须加锁,还是仅仅其中某一句加锁就足够了?我们为什么要加锁呢?分析一下出现lazyloaded的那种情形的原因。原因就是检测null的操作和创建对象的操作分离了。如果这两个操作能够原子地进行,那么单例就已经保证了。于是,我们开始修改代码:publicclassSingletonClass{privatestaticSingletonClassinstanee=null;publicstaticSingletonClassgetInstance(){synchronized(SingletonClass.class){if(instanee==null){instanee=newSingletonClass();}}returninstanee;}privateSingletonClass(){}}首先去掉getinstance()的同步操作,然后把同步锁加载if语句上。但是这样的修改起不到任何作用:因为每次调用getInstance()的时候必然要同步,性能问题还是存在。如果 如果我们事先判断一下是不是为null再去同步呢?publicclassSingletonClass{privatestaticSingletonClassinstanee=null;publicstaticSingletonClassgetInstance(){if(instanee==null){synchronized(SingletonClass.class){if(instanee==null){instanee=newSingletonClass();}}}returninstanee;privateSingletonClass(){}}还有问题吗?首先判断instance是不是为null,如果为null,加锁初始化;如果不为null,直接返回instance。这就是double-checkedlocking设计实现单例模式。到此为止,一切都很完美。我们用一种很聪明的方式实现了单例模式责任链问题A:实行一个过滤功能,过滤一段文字首先获取用户输入的一段文字:Stringmsg="大家好:),<script>,敏感,被就业,网络授课没感觉,因为看不见大家伙儿";那么我们写一个filterMethod(){};使用最简单的replace方法替换文中的敏感词问题B:如果想用面向对象的方法去实现呢?创建一个类MsgProcessor专门用来处理用户输入的文字,该类用一个属性message(用户输入文字),生成set/get方法,(为什么要通过set/get方法去访问属性,而不直接访问该属性???为了保护该属性,不让用户直接访问修改,如果是你的存折,你可以在set/get方法中加入权限判断,避免让用户直接访问操作;如果让该属性只能够看,不能够修改,则直接删除set方法即可)一个方法process()(处理文字) 每次只需要将MsgProcessormp=newMsgProcessor();mp.setMsg(msg);cess();问题C:如果我们有多个过滤器,那么如何设计会更加方便以后继续添加??首先我们写一个接口Filter,它有一个doFilter方法,publicinterfaceFilter{StringdoFilter(Stringstr); }制作接口相当于给所有开发人员制定了规范,然后我们写的每一个过滤器类都要实现该接口,由于有多个过滤器类,所以我们建立一个过滤器类的集合类FilterChain,它需要实现Filter接口,同时要拥有过滤器集合变量publicclassFilterChainimplementsFilter{用集合的好处当有新的过滤器或者过滤器集合类要添加进来,会更加方便List<Filter>filters=newArrayList<Filter>();publicFilterChainaddFilter(Filterf){//能够将子类生成的对象赋值给父类,但是不能将父类生成的对象赋值给子类

//并且能够将实现接口的类的对象赋值给父类接口,同上一样this.filters・add(f);returnthis;//返回this,也就是返回FilterChain本身对象}publicStringdoFilter(Stringstr){Stringr=str;for(Filterf:filters){r=f.doFilter(r);} //逐个调用过滤器的dofilter方法returnr;}那么单个的过滤器例如HTMLFilter,只需要执行自己的操作publicclassHTMLFilterimplementsFilter{@OverridepublicStringdoFilter(Stringstr){//processthehtmltag<>Stringr=str.replace('<','[')・replace('>',']');returnr;}}通常我们不希望这样添加Filter[]filters={newHTMLFilter(),newSesitiveFilter(),newFaceFilter()};因为这样会使得每次只要添加新的过滤器,都要修改这个类,所以我们直接使用集合。那么在main函数中,由于addFilter返回的this,所以可以连写FilterChainfc=newFilterChain();fc.addFilter(newHTMLFilter())・addFilter(newSesitiveFilter())・addFilter(newFaceFilter());问题D:如何继续优化该段代码呢?我们希望msgProcess的process方法执行何功能?也就是需要在MsgProcessor类中加入成员变量FilterChainfc;publicStringprocess(){returnfc.doFilter(msg);}那么要想用MsgProcessor类的对象调用process方法,就必须要在MsgProcessor类中生成fc的set/get方法;Stringresult=cess();问题E:回顾流程1、 封装用户输入的文本,成员变量msg(文本),Fc(过滤器对象)成员方法process(处理文本)2、 建立过滤器接口,制定规范3、 创建过滤器集合类,每增加一个过滤器,都添加到集合中去,完成父类方法,循环调用集合中所有过滤器的方法4、 如果新加一个过滤器,完成好类实现之后,只需要在main方法中加入进去即可,方便调节过滤器的执行顺序问题F:以上我们只做了从客户端发送到服务器端的文本处理,如果我们也希望同时处理服务器端到客户端的文本,那么该如何做?该实现的思想与struets中拦截器的实现思想一致理解堆栈的思想,先进后出;也就是说,当我们通过服务器端的拦截器1,2,3,4处理完文本后,再返回到客户端之前,仍然需要进行拦截器的处理,只不过执行顺序是拦截器4,3,2,1。首先接口Filter,我们需要修改其doFilTeR方法voiddoFiITer(RequesTrequesT,Responseresponse,FilTerChainchain);在main函数中,我们创建模拟的RequesT,Response类Stringmsg="大家好:),<scripT>,敏感,被就业,网络授课没感觉,因为看不见大家伙儿";RequesTrequesT=newRequesT();requesT.seTRequesTSTr(msg);Responseresponse=newResponse();response.seTResponseSTr("response");然后通过FilTerChain进行处理,只不过需要将doFilTer方法改写@OverridepublicvoiddoFilter(Requestrequest,Responseresponse,FilterChainchain){//如果已经达到过滤器集合的数目,就返回if(index==filters・size())return;//获取当前过滤器Filterf=filters・get(index);//加1,使下次调用下一个过滤器index++;f・doFilter(request,response,chain);}那么同时也要改写HTMLFilter类,假设该类是第一个添加到集合类中@OverridepublicvoiddoFilter(Requestrequest,Responseresponse,FilterChainchain){//processthehtmltag<>request・requestStr=request・requestStr.replace('<','[').replace('>',']')+"——HTMLFilter()";chain.doFilter(request,response,chain);response.responseStr+="——HTMLFilter()";}那么执行第一步,处理request传来的字符串,执行到第二步时,执行dofilter方法重新调用到filterChain的dofilter方法,但这时index++,会调用第二个过滤器类的方法。依次循环,直到if(index==filters・size())return;就会执行下一句第三步,也就是处理response工产系列老张手拿AK47,嘴里叼着雪茄,开着奔驰车,一路哼着歌奔向东北一个人拥有这么多东西,相当于一个工厂,于是我们帮他设计一个抽象工厂类,由于是具体的我们给它设计成抽象类,而非接口publicabstractclassAbstractFactory{publicabstractVehiclecreateVehicle();publicabstractWeaponcreateWeapon();publicabstractFoodcreateFood();}当然Vehicle、Weapon、Food这些肯定也会弄成抽象类。publicabstractclassFood{publicabstractvoidprintName();}publicabstractclassVehicle{publicabstractvoidrun();}publicabstractclassWeapon{publicabstractvoidshoot();}也就由具体的类去继承并实现其抽象方法例如:publicclassCarextendsVehicle{publicvoidrun(){System,out.println(”冒着烟奔跑中car ");}}publicclassAK47extendsWeapon{publicvoidshoot(){System,out.println("哒哒哒・・・");}}publicclassAppleextendsFood{publicvoidprintName(){System,out・println("apple");}}好的,那么我们设计一个默认的工厂publicclassDefaultFactoryextendsAbstractFactory{@Overridep

温馨提示

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

评论

0/150

提交评论