选择Java接口还是抽象类(2)

2008-02-23 09:40:04来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折


  
  
  
  public abstract Motor{
  
  abstract public int getHorsepower();
  
  }
  
  
  
    在Motor抽象类的基础上构造出多种具体实现,例如A型发动机、B型发动机等,再加上系统的其它部分,最后得到1.0版的软件并交付使用。一段时间过去了,现在要设计2.0版的软件。在评估2.0版软件需求的过程中,发现一小部分发动机是电池驱动的,而电池需要一定的充电时间。销售部门的人希望能够通过计算机查阅充电时间。根据这一要求定义一个新的行为,如图1所示。
  
    行为2:查询电驱动发动机的充电时间,发动机将返回一个表示充电时间的整数。
  
    用Java方法来描述这个行为,代码如下:
  
  
  
  public abstract BatteryPoweredMotor extends Motor{
  
  abstract public int getTimeToRecharge();
  
  }
  
  
  
    在销售部门的软件中,电驱动发动机也以类的形式实现,但这些类从BatteryPoweredMotor而不是Motor派生。这些改动加入到2.0版软件之后,销售部门很满意。随着业务的不断发展,不久之后光驱动的发动机出现了。销售部门要求光驱动发动机需要一定光能才能运转,光能以流明(Lumen)度量。这个信息对客户很重要,因为下雨或多云的天气里,某些光驱动发动机可能无法运转。销售部门要求为软件增加对光驱动发动机的支持,所以要定义一个新的行为。
  
    行为3:查询光驱动发动机能够正常运转所需要的最小流明数,发动机返回一个整数。
  
    再定义一个抽象类并把行为3转换成Java方法,代码如下:
  
  
  
  public abstract SolarPoweredMotor extends Motor{
  
  abstract public int getLumensToOperate();
  
  }
  
   
  
    如图1所示,SolarPoweredMotor和BatteryPoweredMotor都从Motor抽象类派生。在整个软件中,90%以上的代码以相同的方式对待所有的发动机。偶尔需要检查一下发动机是光驱动还是电驱动,使用instanceof实现,代码如下:
  
  [color=#336600]
  
  if (instanceof SolarPoweredMotor){...}
  
  if (instanceof BatteryPoweredMotor){...}
  
  
  
    无论是哪种发动机,马力这个参数都很重要,所以在所有派生的抽象类(SolarPoweredMotor和BatteryPoweredMotor)中,getHorsepower()方法都有效。
  
    现在销售部门又有了一种新的发动机,它是一种既有电驱动又有光驱动的双重驱动发动机。光驱动和电驱动的行为本身没有变化,但新的发动机同时支持两种行为。在考虑如何定义新型的光电驱动发动机时,接口和抽象类的差别开始显示出来了。新的目标是在增加新型发动机的前提下尽量少改动代码。因为与光驱动发动机、电驱动发动机有关的代码已经过全面的测试,不存在已知的Bug。为了增加光电驱动发动机,要定义一个新的SolarBatteryPowered抽象类。如果让SolarBatteryPowered从Motor抽象类派生,SolarBatteryPowered将不支持针对光驱动发动机和电驱动发动机的instanceof操作。也就是说,如果查询一个光电驱动的发动机是光驱动的,还是电驱动的,得到的答案是:都不是。
  
    如果让SolarBatteryPowered从SolarPoweredMotor(或BatteryPoweredMotor)抽象类派生,类似的问题也会出现,SolarBatteryPowered将不支持针对BatteryPoweredMotor(或SolarPoweredMotor)的instanceof操作。从行为上看,光电驱动的发动机必须同时从两个抽象类派生,但Java语言不允许多重继承。之所以会出现这个问题,根本的原因在于使用抽象类不仅意味着定义特定的行为,而且意味着定义实现的模式。也就是说,应该定义一个发动机如何获得行为的模型,而不仅仅是声明发动机具有某一个行为。
  
  通过接口建立行为模型
  
    如果用接口来建立行为模型,就可以避免隐含地规定实现模式。例如,前面的几个行为改用接口定义如下。
  
    行为1:
  
  
  
  public interface Motor(){
  
  public int getHorsepower();
  
  }
  
  
  
  行为2:
  
  
  
  public interface BatteryPoweredMotor extends Motor(){
  
  public int getTimeToRecharge();
  
  }
  
  
  
  行为3:
  
  
  
  public interface SolarPoweredMotor extends Motor{
  
  abstract public int getLumensToOperate();
  
  }
  
  
  
    现在光电驱动的发动机可以描述为:
  
  [color=#336600]
  
  public DualPoweredMotor implements SolarPoweredMotor, BatteryPoweredMotor{}
  
  
    DualPoweredMotor只继承行为定义,而不是行为的实现模式,如图2所示。
  
    在使用接口的同时仍旧可以使用抽象类,不过这时抽象类的作用是实现行为,而不是定义行为。只要实现行为的类遵从接口定义,即使它改变了父抽象类,也不用改变其它代码与之交互的方式。特别是对于公用的实现代码,抽象类有它的优点。抽象类能够保证实现的层次关系,避免代码重复。然而,即使在使用抽象类的场合,也不要忽视通过接口定义行为模型的原则。从实践的角度来看,如果依赖于抽象类来定义行为,往往导致过于复杂的继承关系,而通过接口定义行为能够更有效地分离行为与实现,为代码的维护和修改带来方便。

上一篇: Motorola的按键值
下一篇: 搭建WAP应用开发环境

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:Java Network Programming 笔记(1)

下一篇:将Java程序作成exe文件的几种方法