最大化Java代码的可重用性

发表于:2009-10-30 10:43

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:未知    来源:51Testing软件测试网采编

#
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() { return pPolygon.containsPoint(this, p);}
  …
  }

  在此处,nPolygon应该是这个样子:

  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表示该类的唯一目的是组织公共静态过程。在Java中,类的名字以小写字母开头不是一种标准的做法,但象pPloygon这样的类事实上并不执行普通类的功能。也就是说,它并不代表着一类对象,它只是语言本身所需要的用于代码组织的实体。

  在上面这个例子中,改动代码的总体影响是使得客户代码不必为了重用其功能而从Polygon继承。Polygon类的功能现在已经由pPolygon类以过程为单位提供。客户代码只使用自己需要的代码,无需关心自身并不需要的功能。

  这并不意味着在这种新型的过程化编程模式中,类不服务于更有用的目的。恰恰相反,类执行组织和封装对象数据成员的必要工作。而且它们通过多重接口实现多态性的能力也为代码重用提供了显著的支持,这将在下一个步骤中讨论。然而,由于将功能实现包含在实例方法中无法实现理想的代码重用,所以通过类继承实现代码重用和多态性支持也不应成为最佳的技术选择。

  在一本被广为阅读的书《Design Patterns》中曾简要地提及一种略有不同的技术。策略模式(Strategy Pattern)提倡将相关算法的每个成员封装在一个通用的接口下,以便于客户端代码可交换地使用其算法。由于一个算法通常被作为一个或几个独立的过程进行编码,这种封装更注重执行单独任务的过程的重用,而不是执行多种任务的、包含代码和数据的对象的重用。这一步骤体现了相同的基本思想。

  然而,将一个算法封装在一个接口下意味着将算法作为实现接口的对象进行编码。这意味着我们仍然依赖于一个与所包装的对象的数据和其他方法相耦合的过程,这样便会使其复用变得复杂。此外还存在这样一个问题,每次需要使用这个算法的时候都必须实例化这些对象,这便会降低程序的性能。值得庆幸的是,设计模式提供了针对这两个问题的解决方法。可以在对策略对象进行编码时应用享元模式(Flyweight Pattern,译者注:还存在一种译法为轻量模式),这样每个对象只会存在一个被共知共享的实例(这针对程序性能的问题),而且每个共享对象在访问间隔中并不维持状态(于是对象将没有数据成员,这针对大多数的耦合问题)。由此产生的享元--策略模式非常类似于在这一步骤中所提到的将功能实现封装在全局可见的、无状态的过程中的技术。(译者注:以上这两段文字读起来可能有些晦涩难解,建议有兴趣的读者参阅文中所提到《设计模式》一书,Erich Gamma等著、李英军等译、机械工业出版社出版。)

21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号