第18卷第3期
刘
冰:基于Java代码重用性的研究
·61·
出一个接口(interface或者一个抽象类)(abstractclass。)这样,当需要用其它组件完成任务时,只需要替换该接口的实现,而程序代码的其它部分则不需要改变。若现有的组件不能满足要求时,可以创建新的组件,实现该接口,或者直接对现有的组件进行扩展,由子类去完成扩展的功能。在具体开发实践中,通常从下面两个方面来使用接口:一是把参数类型改成接口,二是尽量选择最简单的参数接口类型。(1把参数类型改成接口)众所周知,Java语在
选择:staticpublicbooleanareOverlapping(Rectangularrect1,Rectangularrect2){……}上面的代码假定Window类型实现了Rectangular接口。经过改动之后,对于任何矩形对象我们都可以重用该方法的功能。2.2代码分离由于Java面向对象的特点,继承的方法无疑也能实现代码的重用,但这并不是最理想的方法。因为,继承总是带来一些多余的方法和数据成员,这样就会使得重用类里面的某个方法的代码变得复杂;另外,派生类对父类的依赖关系也会使得代码更加复杂:因为对父类的改动就极可能影响到子类;同时,修改父类或者子类中的任意一个类时,则很难记得哪一个方法被子类覆盖,哪一个方法没有被子类覆盖;最后,子类中的覆盖方法是否要调用父类中的对应方法有时并不是那么明显。这样,仅仅通过继承来实现代码的重用就存在一定的不足。在实际编程中,通常是将继承与代码分离技术相结合来实现代码的重用。所谓代码分离就是将可变的部分和不可变的部分分离开来,它是面向对象设计的一个重要原则。在通过继承进行代码重用的时候,可以在抽象基类中定义好不可变的部分,而由其子类去具体实现可变的部分,这样,不可变的部分就不需要重复定义,而且也便于维护。2.3改写类的实例方法在实际编程中,代码重用的首选应是那些执行单一概念任务的方法。为了重用这些代码,可把类的某些实例方法移出成为全局性的过程。若要提高这种过程的可重用性,过程代码应该象静态工具方法一样进行编写:即它只能使用自己的输入参数,并调用其他全局性的过程,但不能使用任何非局部的变量。显然,这种对外部依赖关系的限制简化了过程的应用,从而使得过程能够方便地用于任何地方。众所周知,Java中,在方法是不能脱离类而单独为了实现代码的重用,就可以将相关的存在的。因此,过程进行有效的组织并使它们成为一个独立类中的公共静态方法。例如,对于如下所示的一个类:classPolygon{…publicintgetPerimeter(){……}publicbooleanisConvex(){……}publicBooleancontainsPoint(Pointp){……}
言里,如果某个方法的所有参数都是对一些已知接口的引用,那么这个方法就能够操作那些实际上可能还没有实现该接口的类的对象。在实际编程中,若某块代码能够编写为独立的public方法时,只要能够把它所有类形式的参数改为接口形式,那么方法的参数就可以是实现了该接口的所有类的对象,而不仅仅是原来的类所创建的对象。这样,该方法就能够对可能存在的大量的对象类型进行操作。例如,对于下面的public静态方法:staticpublicbooleancontains(Rectanglerect,intx,inty){……}若将rect参数的类型Rectangle类改变成接口类型:publicinterfaceRectangular{RectanglegetBounds();}那么所有可以描述为矩形的类(即,实现了Rectangular接口的类)所创建的对象都可以作为提供给contains(Rectanglerect,intx,inty){……}的rect参数,这样,显然提高了代码的重用性。这种通过放宽参数类型的限制,即把方法的参数类型改成接口是实现代码可重用性的一个很好的方法。(2选择最简单的参数接口类型)在把参数的类型改为接口类型时,可能存在多种实施
方案,在这些方案中,对代码重用最有价值的应是那种既能完全满足方法对参数的需求,同时又具有最少的多余代码和数据的方案。事实上,描述参数对象要求的接口越简单,其他类实现该接口的机会就越大,其对象能够作为参数使用的类也越多。下面以一个简单的例子来说明这一点:staticpublicbooleanareOverlapping(Windowwindow1,Windowwindow2){……}这个方法用于检查两个窗口(假定是矩形窗口是)否重叠。如果这个方法只要求从参数获得两个窗口的矩形坐标,此时相应地简化这两个参数是一种更好的
·62·
电
脑
与
信
息
技
术
2010年6月
…}就可以将它改写成下面的形式:classPolygon{…publicintgetPerimeter(){returnpPolygon.computePerimeter(this);}publicbooleanisConvex(){returnpPolygon.isConvex(this);}publicbooleancontainsPoint(){returnpPolygon.containsPoint(this,p);}…}在这里,nPolygon应该是:classpPolygon{staticpublicintcomputePerimeter(Polygonpolygon){...}staticpublicbooleanisConvex(Polygonpolygon){...}staticpublicboolean