2013年6月25日 星期二

abstract class vs interface

對於從事JAVA的開發人員來說,

抽象類這個概念應該並不陌生,

但實際上這兩個的差異似乎又說不上來,

最近剛好有朋友問到這個部分,

索性就把自己研究的心得分享一下。

程式面的差異



在abstract class中,由於可以繼承的關係,你當然可設定任何作用域的成員變數,

也可以寫abstract和非abstract的方法,差異只是繼承的類必須實作abstract的方法,

非abstract的方法會直接繼承,或者子類可以改寫。

而interface中,你只能實作,想當然你的成員變數一定是public的,

實作interface的類也不能出現重複的屬性,所以interface的屬性也一定是static & final的,

interface中的方法一定是abstract的,實作的類也一定要實作該方法。

概念的差異

在JAVA中只能單一繼承,但是可以實作多個介面,

抽象類可以定義自己的屬性和方法和抽象方法,

從繼承的角度上很容易將子類和其繼承的抽象類聯想為is a的關係,

而類別實作介面時也必須同時實作其中的抽象方法,

介面也並無強調和其實作類的關係,

因此你可以想像成是like a的關係。

實例比較

下面我用一個簡單的例子說明兩者使用的時機和差異性,

如果有發現錯誤或改正的地方煩請不吝指教,

假設我們現在要設計一個抽象的類別 - 車,

車有兩個基本的方法是加速 speed() 和剎車 stop(),

以abstract class的方式定義如下:

public abstract class Car{
  abstract void speed();
  abstract void stop();
 }

以interface的方式定義如下:

public interface Car{
  void speed();
  void stop();
 }

表面上看起來差異不大,

但如果今天要增加一個新的功能叫倒車顯影 backView(),

如果你加在abstract class內,

public abstract class Car{
  abstract void speed();
  abstract void stop();
  abstract void backView();
 }

問題來了,那是不是所有繼承車的子類都要實作這個方法,

而且難道所有車的子類,所有廠牌的車子都有倒車顯影嗎??

想必不是,那如果放在interface呢??

public interface Car{
  void speed();
  void stop();
  void backView();
 }

道理一樣,原本實作car的類也全部被強制要實作 backView(),

想必這也是不合理的,以下的方式比較正確:

public abstract class Car{
  abstract void speed();
  abstract void stop();
 }
 
 public interface BackView{
  void backView();
 }
 
 public class Toyota extends Car implements BackView{
  public void backView() {}
  void speed() {}
  void stop() {}
 }

Toyota的本質概念上是一種車,而具有倒車顯影的功能,

從這裡判斷 is a 和 like a 應該很好理解了。

沒有留言:

張貼留言