资源描述
单击以编辑母版标题样式,单击以编辑母版文本样式,第二级,第三级,第四级,第五级,第六章 面向接口而非实现进行编程,6,第六 章,API,是文档的说明和接口的说明总称。通常类的组成是包括公开和非公开的成员两部分。,上一章说到:,API,公开的内容越少越好,。,将代码分成接口和实现两部分,在编写代码时,让系统的其它部分只依赖于接口这是我们呈现设计的习惯。,接口,是用来公开给使用只的说明部分,实现是类内部的具体实现过程。,方法,添加容易,与,移去难,设计者带来的问题往往远远多于其解决的问题。向,API,中添加一个,新方法是很容易,的一件事,但与此相反,,想从,API,中移徐一个方法,却非常困难。一个,API,对外提供的功能越多,,那么为保持,向后兼容性,所做的工作也就越多。提供的,功能越,多留给具体,实现的空间也就越少,。如果,API,公开的不必要的内容越多,可改进的,空间也就越少,。,方法的添加与移去,1,代码不是,API:,需要经过抽象的说明才是,API,,没有经过重构,那么公开的很可能不是,API,,而是内部的具体实现。千万不要把代码当成,API,,还要花精力来整理。,2,公布的是接口不是实现,:给调用者是接口应用,不是公布类的具体实现描述。,3,逻辑分离与物理分离,:,只是把类说明,和类实现分离,但文件还是在以前。,4,物理分离:,接口说明和实现说明分别在两个不同的文件中,达到物理的分离。,公布的是接口不是实现,编程应该面向接口而非现实,:在使用,API,时,应该遵守正确的原则。,不要依赖没说明的属性和文件资源,:不要去依赖那些没有在文档中提起的属性和文件资源。,提出合适,API,要求,:正确的做事方法是向设计者要求提出合适,API,。那种自用示公开内容来完成某种功能的做法是非常脆弱的,会因为版本、环境的不同而无法正常运行。,编程应该面向接口而非现实,正确理解面向接口编程的概念,Iterface,只是接口说明,:能够清楚地理解面向接口编程并不是对应着,Java,中的,Iterface,这种编程方式只是将其抽象定义与实际的实现这两类内容进行分离。,类的使用特点,:何时使用类,接口使用特点:,何时使用接口,6.1,移除方法或者字段,不要随意移去方法和属性,:,(1),设计方法或属性在使用:,(2),类会对相关的方法和属性设置访问权限。,(3),类的成员被继承:,设计方法或属性在使用,从已经公开的类或者接口中移除方法或者字段是一件错误的事情。系统公开,可能说明给方法或属性具有一定使用代表性,这样就会有其他成员在使用。,一个方法或者字段被定义为,private,或者是默认的,package,访问级别,那么对于外部代码来说,它是不可见的,也就无法进行访问。这种情况,从类中移除该内容,不会引起什么问题,但没什么意义。,类对相关方法和属性设置访问权限,类的设计者肯定会对类的成员根据实际使用需要设置成:,PUBLIC,PROTECTED,PRIVATE,等,如果你移去,就会造成该给访问的没办法访问,不能访问的有多此一举。,移去方法,对于源代码和二进制来讲,移除一个抽象的,proteced,方法是可以兼容的。从功能角度来说,可能是并不兼容。那个方法当时被动放到类中,应该是有本应 的目的,而子类也可能是会重载该是方法,并希望在合适的时候被动调用。他们的实现就不能被调用了,,theMethod,方法语义也发生了改变,则子类是无法重载这个方法的。,6.2,移除或者添加一个类或者接口,如果一个类或者接口可以被外部访问,就意味着其方法可能会被调用,或者其字段可能被引用,一旦类和接口成为,API,,两者就没什么区别了,都必须长久地存在下去。,类和接口其实是没有很大区别,,类强调封装性,,,接口强调调用方法,或,引用,方法。,6.3,向现有的继承体系中添加接口或者类,向现有的继承体系中添加类或者接口可以带来很多好处:,(,1,)简化,API:,不必要公开那么多,(,2,)引同更统一,(,3,)维护更方便,例子说明,Public abstract String sayHello();,Public abstract String sayHelloto(String wgo);,作者希望可以简化这个,API,Public abstract class SimpleHelloClass,Public abstract String sayHello();,当然,以前编写的类仍然需要维护。,Public abstract class helloClass extends SimpleHelloClass,简单 只需要维护这里就可以,工厂方法支持参数化的返回类型(,2,),Public final class Template extends object,Private final Class type;,Public Template(Class type this.type=type;,Public Class getType()return type;,/now what!?,Public Template()this(object.class);,工厂方法支持参数化的返回类型(,3,),Public final class Template extends object,Private final Class type;,Public Template(Class type this.type=type;,Public Class getType()return type;,Deprecated,SuppressWarnings(“unchecked”),Public Template()this(Class)object.class);,Public static Template create(),Return new Template(object.class),5.3,让所有的内容都不可更改,不考虑让其拥有子类,这个类不能被继承。否则,API,一旦发布以后,会有各种使用方式,大量无法预计的事情。,Public class Hello,Public void hello()System.out.println(“Hello”);,直接公开这个可被继承的,Hello,类,会有很多代码,是直接从外部调用,Hello,的,Hello,方法的:,Public static void sayHello(),Hello Hello=new Hello();,Hello.Hello();,各种使用方式,开发人员也可编写一个继承,Hello,的类,MyHello,重载,hello,方法,代码如下。,Private static class MyHello extends Hello Override,Public void hello()System.out.println(“Hi”);,Private static class SuperHello extends Hello Override,Public void hello(),Super.hello();,System.out.println(“Hello once again”);,6.4,添加方法或者字段(,1,),(1),尽量少用字段:,应该避免在允许继承的类或者接口中添加新的抽象方法。如果是类,请确保该类不可被继承。,(,2,),添加一个抽象方法,可能不向后兼容,:,向类中添加一个抽象方法,则会强迫其非抽象的子类来实现该是抽象方法,这种改变是做不到向后兼容的。这种处理对于源代码来说是不兼容的。,6.4,添加方法或者字段(,2,),(3),避免继承类添加新抽象方法,:,在对,API,进行改进时,与方法相比,字段受到的约束更多。这正是要避免在,API,中使用字段的原因;当然那种使用,static,和,final,声明的常用字段是可以添加到,API,中的。,(,4,)不要在接口中添加一个非抽象方法,:能添加抽象方法的只能是类,不可能在接口中添加一个非抽象方法。无论是向一个类还是一个接口中添加一个方法,只要这两者可以被继承,那么这种改变就做不到了百分百兼容。,6.5 Java,中接口和类的区别,多继承,:,Java,接口最突出的特性就是多继承。因为多继承可以减少对内存的占用。利用多继承公使用一个对象,就可以实现,API,中公开的多个接口。,类继承,:类继承则只能有一个父类,此时如果类之间有些数据需要互访或者调用方法,那么只能用委托的方式。这样会占用很多空间,如果只是一两个,就不是那么明显了。性能方面的考虑就不是主要因素了。,6.6,弱点背后的优点(,1,),向现有接口中添加方法总不太容易。要向后兼容的话,那么添加方法就不是有多困难的问题,而是几乎不可能完成的任务。,(,1,),方法维护麻烦,(,2,),引用麻烦,(,3,),版本保持向后兼容麻烦,那么就利用不祝来改变设计方法:,采用多版本命名接口,保持系统兼容。,对于语言的不同版本,要决定分别支持哪些功能。接口是一个非常合适的工具,6.6,弱点背后的优点(,2,),Public interface InstanceProvide,Public Class instanceClass()throws exception;,Public Object instanceCreate()throws Exception;,把常用的专用到一个类中,提高整体运行效率。,创建了如下这个接口:,Public interface BetterInstanceProvider extends InstanceProvider,Public Boolean isInstanceof(Class c);,6.6,弱点背后的优点(,3,),If(instance instanceof BetterInstanceProvider),betterInstanceProvider bip=(BetterInsatnceProvider)instance;,return bip.isInstanceof(string.class);,else Return string.class.isAssignableFrom(instance.instanceClass();,6.7,添加方法的另一种方案(,1,),禁止类被继承,:利用,final,:把一个类声明为,final,,就表示这个类是不可被继承的。因此那种在接口或者抽象类中添加方法而引起的问题,对于这个,final,类来说就不会出现了。由于在类的二进制文件中,对于要调用的方法,是可以通过名称、参数及返回值来唯一确定的,所以不会产生兼容性的问题。,不要定义具有相同数量参数同名方法,:像,theObject.add(null),这句代码,编译器就会给出一个编译错误,这这句代码中要方法具有二义性。要避免的方法很简单,就是不要加入具有相同数量的参数的同名方法。,6.7,添加方法的另一种方案(,2,),Imporllable;,Public,final,class InstanceProvider,Private final Callable instance;,Public InstanceProvider(Callable instance),This.instance=instance;,Public Class instanceClass()throws Exception,Returll().getClass();,Public Object instanceCreate()throws Exception,Returll();,6.7,添加方法的另一种方案(,3,),Public abstract class Accessor,Private static volatile Accessor DEFAULT;,Public static Accessor getDefauIt(),Accessor a=DEFAULT;
展开阅读全文