首页 > 图灵资讯 > 技术篇>正文

提高Java代码可重用性的三个措施

2024-03-03 10:35:24

  三种提高Java代码可重用性的措施 本文介绍了三种修改现有代码以提高可重用性的方法,即将参数类型改为接口,选择最简单的参数接口类型。

  措施一:改写类实例方法 代码重用不是通过类继承实现的精确代码重用技术,因此不是最理想的代码重用机制。换句话说,如果我们不继承整个类的所有方法和数据成员,我们就不能重用这个类的单一方法。继承总是带来一些多余的方法和数据成员,它们总是使重用类中某种方法的代码复杂化。此外,衍生类对父类的依赖也使代码进一步复杂:父类的变化可能会影响子类;在修改父类或子类中的任何类别时,我们很难记住哪种方法被子类覆盖,哪种方法没有被子类覆盖;最后,子类中的覆盖方法是否应调用父类中的相应方法有时并不明显。 任何方法,只要它执行一个单一概念的任务,就其本身而言,它应该是可重用代码的首选。为了重用这个代码,我们必须回到面向过程的编程模式,将类的实例方法移出到整个过程中。为了提高这个过程的可重用性,过程代码应该像静态工具方法一样编写:它只能使用自己的输入参数,只能调用其他全球过程,不能使用任何非局部变量。这种对外部依赖关系的限制简化了过程的应用,使过程在任何地方都能轻松使用。自然,因为这种组织方式总是使代码具有更清晰的结构,即使是不考虑重用性的代码也能从中受益。 在Java中,方法不能脱离类而单独存在。因此,我们可以将相关过程组织成独立的类别,并将其定义为公共静态方法。 例如,对于以下类别: class Polygon {. . public int getPerimeter() {...} public boolean isConvex() {...}public boolean containsPoint(Point p) {...} . . }我们可以把它改写成: class Polygon {. . public int getPerimeter() {return pPolygon.computePerimeter(this);}public boolean isConvex() {return pPolygon.isConvex(this);} public boolean containsPoint(Point p) {return pPolygon.containsPoint(this, p);} .}其中,ppolygon是: class pPolygon { static public int computePerimeter(Polygon polygon) {...} static public boolean isConvex(Polygon polygon) {...} static public boolean containsPoint(Polygon polygon, Point p) {...} }从ppolygon这个类的名字可以看出,这个类的封装过程主要与polygon类型的对象有关。名字前面的p表示,这种类型的唯一目的是组织公共静态过程。名字前面的p表示,此类的唯一目的是组织公共静态过程。在Java中,以小写字母开头的类名是非标准的,但像PPloygon这样的类实际上并不提供普通的Java功能。也就是说,它并不代表一种对象,它只是Java语言组织代码的一种机制。 在上面的例子中,更改代码的最终效果是使用Polygon功能的客户代码不再需要从Polygon继承。ppolygon类的功能现在已经由ppolygon类提供。客户代码只使用自己需要的代码,不需要关心Polygon中不需要的功能。但这并不意味着在这种新的过程编程中的作用被削弱。相反,类在组织和包装对象数据成员的过程中起着不可或缺的作用,正如本文下面介绍的,类通过多个接口实现多态性的能力本身也带来了优秀的代码重用支持。但是,通过类继承实现代码重用和多态性支持并不是最理想的,因为用实例方法封装代码功能并不是代码重用的首选手段。

  措施二:将参数类型改为接口 就像Allen一样 Holub在《Build User Interfaces for Object-Oriented Systems》在面向对象编程中,代码重用的真正关键在于通过接口参数类型使用多态性,而非类继承: “...我们通过对接口而不是对类编程来实现代码重用的目的。如果一种方法的所有参数都引用了一些已知接口,那么这种方法可以操作这些对象:当我们编写方法的代码时,这些对象甚至不存在。如果一种方法的所有参数都引用了一些已知界面,那么这种方法可以操作这些对象:当我们编写方法代码时,这些对象甚至不存在。从技术上讲,可重用的是方法,而不是传递给方法的对象。” Holub的观点应用于“措施1”的结果。当一个代码可以写成一个独立的整体过程时,只要将其所有类型的参数改为接口形式,我们就可以进一步提高其可重用性。经过这一变化,该过程的参数可以是实现该界面的所有类别的对象,而不仅仅是原始类别创建的对象。因此,该过程将能够操作大量可能存在的对象类型。 例如,假设有这样一种全球静态方法: static public boolean contains(Rectangle rect, int x, int y) {...}该方法用于检查指定点是否包含在矩形中。在这个例子中,rect参数的类型可以从rectangle类型改为接口类型,如下所示: static public boolean contains(Rectangular rect, int x, int y) {...}Rectangular接口的定义是: public interface Rectangular {Rectangle getBounds();}现在,所有可以描述为矩形的类(即实现Rectangular接口的类)都可以作为提供给prectangular的对象。.contains()rect参数。通过放宽对参数类型的限制,我们使该方法具有更好的可重用性。 然而,对于上述例子,Rectangular接口的getbounds方法返回Rectangle,您可能会怀疑这是否真的值得。换句话说,如果我们知道传输过程中的对象在被调用时会返回到Rectangle,为什么不直接传输到Rectangle而不是接口类型呢?之所以不这样做,最重要的原因与集合有关。假设有这样一种方法: static public boolean areAnyOverlapping(Collection rects) {...}该方法用于检查给定集合中的任何矩形对象是否重叠。在这种方法的内部,当我们用循环依次访问集合中的每个对象时,如果我们不能将对象cast变成rectangular等接口类型,我们如何访问对象的矩形区域?唯一的选择是将对象cast成为其独特的类型形式(我们知道它有一种返回矩形的方法),这意味着该方法必须事先知道其操作的对象类型,因此该方法的重用仅限于这些对象类型。而这就是前面这个措施试图先避免的问题!

  措施三:选择最简单的参数接口类型 在实施第二种措施时,应选择哪种接口类型来取代给定的类型?答案是哪个界面完全满足了过程中对参数的需求,并且具有最少的多余代码和数据。描述参数对象要求的界面越简单,其他类别实现界面的机会就越大——因此,可以作为参数使用的类别就越多。这一点很容易从下面的例子中看出: static public boolean areOverlapping(Window window1, Window window2) {...}该方法用于检查两个窗口(假设是矩形窗口)是否重叠。如果该方法只需要从参数中获得两个窗口的矩形坐标,那么简化这两个参数是一个更好的选择: static public boolean areOverlapping(Rectangular rect1, Rectangular rect2) {...}以上代码假设Window类型实现了Rectangular接口。改变后,我们可以重用该方法的功能,用于任何矩形对象。 有时,描述参数需求的界面可能有太多的方法。此时,我们应该在整体名称空间中定义一个新的公共接口,以重用其他面临同样问题的代码。 当我们需要像C语言中的函数指针一样使用参数时,创建唯一的界面来描述参数需求是最好的选择。例如,假设有以下过程: static public void sort(List list, SortComparison comp) {...}该方法利用参数中提供的比较对象comp,通过比较给定列表list中的对象对list列表进行排序。sort对comp对象的唯一要求是调用一种比较方法。因此,Sortcomparison应该只有一个方法接口: public interface SortComparison {boolean comesBefore(Object a, Object b);}sortcomparison接口的唯一目的是为sort提供一个所需功能的钩子,因此sortcomparison接口不能在其他地方重用。 总而言之,本文的三项措施适用于按照面向对象的惯例对现有的代码进行改造。这三种措施与面向对象的编程技术相结合,获得了一种新的代码编写技术,可以简化方法的复杂性和依赖性,提高方法的可重用性和内部凝聚力。 当然,这里的三种措施不能用于自然不适合重用的代码。不适合重用的代码通常出现在应用程序的表达层中。例如,创建程序用户界面的代码和连接到输入事件的控制代码都属于程序和程序之间的代码,几乎不可能重用

上一篇 MD5的Java Bean实现
下一篇 java关键字详解(abstract.double.int.switch)

文章素材均来源于网络,如有侵权,请联系管理员删除。