很多人都认为抽象类和接口都“差不多”,于是就随便选一种来开发项目。其实这是一种非常不明智的做法,若选择上稍微有些错误,到了项目开发后期,这些错误将会越来越明显,越来越大,最后直接导致项目的失败。
 
在接口和抽象类的选择上,必须遵守这样一个原则:行为模型应该总是通过接口而不是抽象类定义。为了说明其原因,下面试着通过抽象类建立行为模型,看看会出现什么问题
 
 
 
某发电厂需要开发一套发电机,用来给城市居民供电。发电机的功率是发电厂最为关心的数据,所以当查询发电机的功率时,发电机需要返回一个表示功率的整数。
 
 
 
为了说明用抽象类定义可能出现的问题,下面用抽象类建立发动机的行为模型public abstract class Alternator {
    abstract int getPower();//返回功率
}………… 一段时间过后,客户想要开发一套太阳能发电机,因为成本低且环保。太阳照射在电池板上的热量便成了发电厂关心的数据。于是,发电机必须返回表一个示热量的整型数public abstract class Alternator {
    abstract int getPower();//返回功率
}在这个抽象类的基础上构造出了煤炭发电机。
 
………… 一段时间过后,客户想要开发一套太阳能发电机,因为成本低且环保。太阳照射在电池板上的热量便成了发电厂关心的数据。于是,发电机必须返回表一个示热量的整型数 public abstract class SunAlternator extends Alternator
 {    
     abstract int getSunPower();//返回太阳照射热量
 }
…………
 
又过了一段时间后,客户发现当地经常刮大风,而且风力不小,于是客户想开发一套风力发电机,风速便成了客户关心的数据。于是,发电机必须返回一个表示风速的整数public abstract class WindAlternator extends Alternator
{
    abstract int getWindSpeed();//风速
}
这时,对于这些发电机,发电厂偶尔需要检查一下是太阳能发电还是风力发电,代码如下:
 
if (instanceof SunAlternator){...}
 if (instanceof WindAlternator){...}
 无论什么发电机,功率这个参数很重要。所以在所有具体类中,getPower()方法都有效。
 随着业务的发展,客户想把太阳能和风力结合起来。太阳能发电和风力发电本身行为没有任何变化,但新型的发电机同时支持两种行为。在考虑如何定义新型的发电机时,抽象类和接口的差别开始显示出来了。软件设计原则之一是:以修改最少的代码来应对需求。太阳能发电和风力发电已经过严格的测试,不存在已知的bug。为了开发新型发电机,就需要定义一个SunWindAlternator,如果让SunWindAlternator从抽象类Alternator派生,那么SunWindAlternator将不支持针对太阳能发电和风力发电的instanceof操作,也就是说,当需要检查发电机目前正在以太阳能形式发电还是以风力形式发电,那么得到的答案永远是:都不是。如果让SunWindAlternator从SunAlternator派生,那么得到的答案永远都是:太阳能发电机;从WindAlternator派生也会遇到类似的问题。

解决方案 »

  1.   

    java里面接口是可以多重继承的。我觉得接口更应该是表示 is a 的概念。而抽象类则是is a的一个实现,只是这个实现还不完整,不能单独使用。LZ说的这些情况应该抽象成为接口,这样,比如这个发电机即使风力发电,又是太阳能发电机的时候,那么他们就都是。