




已阅读5页,还剩25页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
设计API时要区分其目标用户群,8,第八章,插件、客户端程序的区别:插件:插件是一种遵循一定规范的应用程序接口编写出来的程序。很多软件都有插件,插件有无数种。例如在IE中,安装相关的插件后,WEB浏览器能够直接调用插件程序,用于处理特定类型的文件。客户端程序:客户服务(CustomerService),是指一种以客户为导向的价值观,它整合及管理在预先设定的最优成本服务组合中的客户界面的所有要素。广义而言,任何能提高客户满意度的内容都属于客户服务的范围之内。,一些程序功能不仅可以直接通过界面进行操作,还可以提供相应的API,以供其他程序来调用,这样第三方程序可以发起通讯,使用相应程序的API指使它完成操作,命令执行完后,控制权返回给调用者。XMMS的API还提供插件支持,第三方可发商可以通过注册“输出插件”来扩展XMMS的功能。它与前面说的客户端的地位完全不同。,第三方的播放场,SPI组成:是与前面说的客户端的地位完全不同。它没有让XMMS进行任何操作。但它为XMMS增加了很多功能,所以此时的插件不是前文所说的“客户端”。XMMS的这种注册插件来扩展功能的方式是SPI(ServiceProviderInterface)的典型应用。,ServiceProviderInterface,为了说明客户端API和SPI区别,Voidxmms_play();Voidxmms_pause();Voidxmms_add_to_list(char*);使用Java语言来定义API的方式则完全不同。PublicclassXMMSPublicvoidplay()doPlay();Publicvoidpause()doPause();PublicvoidaddToPlaylist(Stringfile)doaddToPlaylist(file);,8.1C和Java语言中如何定义API和SPI(1),C和Java语言中如何定义API和SPI(2),在Java中声明API方式有多种。如说可使用static方法、实例方法、抽象方法、以及final方法,这些都是可以的。但编写一个SPI,情况就不同。如果要使用C语言来为XMMS编写程序一个插件的话,必须要写一个支持回放的函数,代码如下:Voidmy_playbackprints(char*text)Printf(“%sn”,text);InterfacePlaybackPublicvoidplayback(bytedata);ClassMyCallbackPrintsimplementsXMMS.PlaybackPublicvoidplayback(bytedata)System.out.println(newString(data);Xmms.registerPlayback(newMyCallbackPrints();,C和Java语言中如何定义API和SPI(3),对于Java程序员,只要所编写的方法不是private、final或者static的,那么就表示该是方法支持调的,而且可以用看成是一个API。对很多程序员,甚至是教师都没有清楚地理解这一点,它也的确不是日常编码的内容。,8.2API演进不同于SPI演进(1),具体的演进方案则还是取决于具体的接口类型:向API中添加一些内容总是可以的,但要移除一些内容则不行。但对于SPI,移除一些内容可以允许,但不允许添加新的内容。建立契约时,必须清楚地区分哪些是API,提供给外面调用,而哪些是SPI,用来让外部来扩展程序功能。设计时容易犯的最大错误就是将API和SPI混在一个类里。根据SPI的契约,不能添加方法,根据API的契约,也不能减少方法。,8.3java.io.Write这个类从JDK1.4到JDK5的演进,还需要使用try/catch/finally的方式来进行防御性编码。TrybufferedWrite.append(what);catch(UnsupportedOpeartionExceptionex)bufferedWrite.write(what.toString();这样来调用API的确有点怪。调用一个方法竟然要写四行代码,java.io.Write的演进(2),假设已有一个优化过Write类,它无须将数据转换成字符串,而是直接处理以提高性能,但用户却可能无法用到这种梦寐以求的优化,PublicclassCountingWriteextendsWritePrivateintcounter;PublicintgetcharacterCount()Returncounter;,java.io.Write的演进(3),OverridePublicvoidwrite(charcbuf,intoff,intlen)throwsIoExceptionCounter+=len;OverridePublicWriteappend(CharSepuencecsq)throwsIoExceptionCounter+=csq.length();Returnthis;。,PrivatestaticfinalclassCDSequenceimplementsCharSequencePrivatefinalintstart;Privatefinalintend;PublicCDSequence()This(0,647*1024*1024);PrivateCDSequence(intstart,intend)This.start=start;This.end=end;Publicintlength()Returnend-start;CountingWriterwriter=newCountingWriter();CDSequencecdImage=newCDSequence();BufferedWriterbufferedWriter=newBufferedWriter(writer);bufferedWriter.append(cdImage);assertEquals(“Correctnumberofwritesdelegated”,cdImage.length(),writer.getCharacterCount();,从JDK1.4到JDK5的演进(4),这个通过覆盖来优化性能的方法却不会被调用,效率仍然没有提高。If(shouldBufferAsTheSequenceIsNotTooBig(csq)Write(csq.toString();elseFlush();Out.append(csq);Returnthis;,从JDK1.4到JDK5的演进(5),首先计算一下字符的数量,如果数量比较小,性能影响也比较小,就使用老的方式处理,否则就先写入当前数据后,再写入大数据。然而,还远远没有结束,还有一个潜在的问题需要解决。PublicclassCryptoWriterextendsBufferedWriterPublicCryptoWriter(Writerout)Super(out);OverridePublicvoidwrite(charbuf,intoff,intlen)throwsIoExceptionChararr=newcharlen;For(inti=0;ilen;i+)Arri=encryptChar(bufoff+i);Super.write(arr,0,len);,从JDK1.4到JDK5的演进(6),OverridePublicvoidwrite(intc)throwsIoExceptionSuper.write(encryptChar);overridePublicvoidwrite(Stringstr,intoff,intlen)throwsIoExceptionStringBuffersb=newStringBuffer();For(inti+0;ilen;I+)Sb.append(encryptChar(str.charAt(off+i);Super.write(sb.toString(),0,len);PrivatecharencryptChar(intc)If(c=Z)ReturnA;If(c=z)Returna;Return(char)(c+1);。,从JDK1.4到JDK5的演进(7),事情变得越来越复杂了!为了处理含有大量字符串的对象等目的,最好是直接将数据写入相应的Writer对象。BooleanisOverriden=false;TryisOverriden=(getClas().getMethod(“write”,String.class).getDeclaringClass()!=Writer.class)|(getClass().getMethod(“write”,integer.TYPE).getDeclaringClass!=BufferedWriter.class)|(getClass().getMethod(“write”,String.class,Integer.TYPE,Integer.TYPE).getDeclaringClass()!=BufferedWriter.class);catch(Exceptionex)ThrowsnewIoException(ex);If(isOverriden|shouldBufferAsTheSequenceIsNotTooBig(csq)Write(csq.toString();elseFlush();Out.append(csq);Returnthis;,反射技术,第三个版本才是最终的解决方案。它使用了反射技术,所以看起来复杂一点,但却是一个非常有效的解决方案。反射技术让这段代码看起来不如原来那么漂亮了,但至少它可以正常运行,结果也是正确的。让一个类可以被动继承,其实就意味着把它当作一个SPI,因为其子类可以提共新技术部的功能,或者说新的服务,但对于代理来说,它更多是让其它的代码来进行调用它的功能,属于功能API,两者是不一样。不能像表面看起来那么简单、顺畅了。,如何避免继承(1),PublicfinalclassWriterPrivatefinalImplimpl;PrivateWriter(Impl,impl)This.impl=impl;Publicfinalvoidwrite(intc)throwsIoExceptionChararr=(char)c;Impl.write(arr,0,1);Publicfinalvoidwrite(charcbuf)thrpwsIoExceptionImpl.write(cbuf,0,cbuf.length);Publicfinalvoidwrite(charcbuf,intoff,intlen)ThrowsIoExceptionImpl.write(cbuf,off,len);Publicfinalvoidwrite(Stringstr)throwsIoExceptionImpl.write(str,0,str.length();,如何避免继承(2),Publicfinalvoidwrite(Stringstr,intoff,intlen)ThrowsIoExceptionImpl.write(str,off,len);Publicfinalvoidflush()throwsIoExceptionImpl.flush();Publicfinalvoidclose()throwsIoExceptionImpl.close();,SPI的提供者类(1),现在写一个SPI的提供者类,这个类中全部都是工厂方法,用来提供Impl接口的具体实现,基本上就是下面这个样子。PublicstaticWritercreat(Implimpl)ReturnnewWriter(impl);PublicstaticWritercreat(finaljava.io.Writerw)ReturnnewWriter(newImpl()PublicvoidWrite(String,str,intoff,intlen)ThrowsIoExceptionw.Write(str,off,len);,SPI的提供者类(2),Publicvoidwrite(chararr,intoff,intlen)ThrowsIoExceptionw.write(arr,off,len);Publicvoidclose()throwsIoExceptonw.close();Publicvoidflush()throwsIoExceptionw.flush();PublicstaticWritercreatBuffered(finalWriterout)Returncreate(newSimpleBuffer(out);PublicstaticinterfaceImplPublicvoidclose()throwsIoException;Publicvoidflush()throwsIoException;Publicvoidwrite(Strings,intoff,intlen)throwsIoException;Publicvoidwrite(chara,intoff,intlen)throwsIoException;,SPI的提供者类(3),PublicfinalclassWriterimplementsAppendablePrivatefinalImplimpl;PrivatefinalImplSeqseq;PrivateWriter(Implimpl,ImplSeqseq)This.impl=impl;Thisseq=seq;Publicfinalvoidwrite(intc)throwsIExceptionIf(impl!=null)Chararr=(char)c;Impl.write(arr,0,1)elseSeq.write(newCharSeq(c);Publicfinalvoidwrite(charcbuf)throwsIoExceptionIf(impl!=null)Impl.write(cbuf,0,cbuf.length);elseSeq.write(newCharSeq(cbuf,0,cbuf.length);,SPI的提供者类(4),Publicfinalvoidwrite(charcbuf,intoff,intlen)ThrowsIoExceptionIf(impl!=null)Impl.write(cbuf,off,len);elseSeq.write(newCharSeq(cbuf,off,len);Publicfinalvoidwrite(Stringstr)throwsIoExceptionIf(impl!=null)Impl.write(str,0,str.length);elseSeq.write(str);Publicfinalvoidwrite(Stringstr,intoff,intlen)ThrowsIoExceptionIf(impl!=null)Impl.write(str,off,len);elseSeq.write(str.subSequence(off,off+len);,SPI的提供者类(5),Publicfinalvoidflush()throwsIoExceptionIf(impl!=null)Impl.flush();elseSeq.flush();Publicfinalvoidclose()throwsIoExceptionIf(impl!=null)Impl.close();elseSeq.flush();,SPI的提供者类(6),设计给客户使用API,最好用final类;而设计SPI的时候,则最好用接口,然后通过一个工厂模式将它们结合在一起。借助“工厂设计模式”尽可能是对客户“隐藏了”相应的复杂度,在API功能时,用户则只看到final类Writer,对于要扩展API功能的人,则只需要看到两个要实现的接口Impl和ImplSeq,所以不管是使用还是扩展这个API,复杂度都不高。虽然根据这个方案写出第一个版本API时,也许工作量会多一些,但是将客户用到功能性API和SPI分离出来,大大降低了演进难度,避免出现将代理与继承混合时出现的那种问题。,8.4合理分解API(1),可以把API分为两类,一类是供他人调用来完成某些功能,还有一类是他人来扩展API功能的,也就是前面说的SP
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 六一活动方案创意方案
- 六一活动绿植活动方案
- 六一游园传统活动方案
- 六一童装活动策划方案
- 六一评奖活动方案
- 六一足球线上活动方案
- 六一颁奖活动方案
- 医生门诊操作考试试题及答案
- 安全色辨识试题及答案
- 药店考试试题及答案胃肠
- 北京市顺义区2023-2024学年五年级下学期数学期末试卷(含答案)
- 2025公基题库(附答案解析)
- 2025年宁夏银川灵武市选聘市属国有企业管理人员招聘笔试冲刺题(带答案解析)
- 机关内部制度管理制度
- 两办意见宣贯考试题及答案
- 2025年高纯硫酸锶项目市场调查研究报告
- 2025年汽车驾照考试科目一考试题库及参考答案
- 广东省广州市天河区2023-2024学年七年级下学期期末考试英语试题(含答案)
- 净水机服务合同协议书
- 古城煤矿压风系统远程监控改造技术协议
- 2025年上海市公务员录用考试《行测》真题及答案解析(B类)
评论
0/150
提交评论