302班

          java突擊隊
          posts - 151, comments - 74, trackbacks - 0, articles - 14
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          abstract classes 與 interfaces的區別

          Posted on 2007-04-19 09:14 停留的風 閱讀(559) 評論(0)  編輯  收藏 所屬分類: Java程序集合

          13. What are the differences between abstract classes and interfaces?

          Abstract classes and interfaces are two different OO concepts and are used differently. An abstract class is similar to an abstract data type. It defines characteristics that are common to any of its subclasses or subtypes. You define characteristics by declaring methods and variables in an abstract class. For example, define an abstract type, Vehicle. In the Java [tm] programming language, an abstract class or method is flagged with the keyword, 'abstract'.
           
           

          public abstract class Vehicle{

          public int wheels;

          public abstract void move();

          }

          The class Vehicle declares behaviours and characteristics that are common to all vehicles. You can define classes which extend vehicle, that are types of vehicles but require more behaviours, such as car or bicycle. Class Vehicle is the abstraction, and car and bicycle add more details to refine the Vehicle behaviour to characterise a car and bicycle object.

          public class Car extends Vehicle{

          public void move(){}

          public void typeOfEngine(){} //Additional behaviour characterise a car

          wheels = 4;

          }

          public class Bicycle extends Vehicle{

          public void move(){}

          wheels = 2;

          public void peddelling(){}

          }

          An interface defines a protocol of behaviour that any class can implement. An interface defines methods, and final static variables. Any class that implements all the interfaces' methods guarantees to behave according to the protocol defined by the interface. Using interfaces ensures that objects can communicate in certain manners.

          Following is an example of an interface:

          public interface TCPProtocol{

          public void open();

          public void close();

          }

          In terms of the Java Platform, there are three main differences in abstract and interface implementation:

          1. A class can implement multiple interfaces but only one superclass.
          2. Abstract classes can implement non-abstract methods, while interfaces can not.
          3. Interfaces are not part of the class hierarchy.

          For more information see
          Writing Abstract Classes and Methods

          Creating Interfaces

          Back to Top

          abstract class和interface有什么區別?

            聲明方法的存在而不去實現它的類被叫做抽象類(abstract class),它用于要創建一個體現某些基本行為的類,并為該類聲明方法,但不能在該類中實現該類的情況。不能創建abstract 類的實例。然而可以創建一個變量,其類型是一個抽象類,并讓它指向具體子類的一個實例。不能有抽象構造函數或抽象靜態方法。Abstract 類的子類為它們父類中的所有抽象方法提供實現,否則它們也是抽象類為。取而代之,在子類中實現該方法。知道其行為的其它類可以在類中實現這些方法。

            接口(interface)是抽象類的變體。在接口中,所有方法都是抽象的。多繼承性可通過實現這樣的接口而獲得。接口中的所有方法都是抽象的,沒有一個有程序體。接口只可以定義static final成員變量。接口的實現與子類相似,除了該實現類不能從接口定義中繼承行為。當類實現特殊接口時,它定義(即將程序體給予)所有這種接口的方法。然后,它可以在實現了該接口的類的任何對象上調用接口的方法。由于有抽象類,它允許使用接口名作為引用變量的類型。通常的動態聯編將生效。引用可以轉換到接口類型或從接口類型轉換,instanceof 運算符可以用來決定某對象的類是否實現了接口。

          選擇將功能設計為接口還是抽象類(在 Visual Basic 中為 MustInherit 類)有時是一件困難的事。“抽象類”是一種不能實例化而必須從中繼承的類。抽象類可以完全實現,但更常見的是部分實現或者根本不實現,從而封裝繼承類的通用功能。有關詳細信息,請參閱抽象類。 

          相反,“接口”是完全抽象的成員集合,可以被看作是為操作定義合同。接口的實現完全留給開發者去做。 接口和抽象類對組件交互都很有用。如果一個方法要求一個參數形式的接口,則任何實現該接口的對象都可以用在該參數中。例如:

          類可能只是從一個基類繼承,所以如果要使用抽象類為一組類提供多態性,這些類必須都是從那個類繼承的。抽象類還可能提供已實現的成員。因此,可以用抽象類確保特定數量的相同功能,但不能用接口這樣做。這里是一些建議,幫助您決定使用接口還是抽象類為組件提供多態性。  

          如果預計要創建組件的多個版本,則創建抽象類。抽象類提供簡單易行的方法來控制組件版本。通過更新基類,所有繼承類都隨更改自動更新。另一方面,接口一旦創建就不能更改。如果需要接口的新版本,必須創建一個全新的接口。

          如果創建的功能將在大范圍的全異對象間使用,則使用接口。抽象類應主要用于關系密切的對象,而接口最適合為不相關的類提供通用功能。 如果要設計小而簡練的功能塊,則使用接口。如果要設計大的功能單元,則使用抽象類。 如果要在組件的所有實現間提供通用的已實現功能,則使用抽象類。抽象類允許部分實現類,而接口不包含任何成員的實現。 
              如果預計要創建組件的多個版本,則創建抽象類。抽象類提供簡單易行的方法來控制組件版本。通過更新基類,所有繼承類都隨更改自動更新。另一方面,接口一旦創建就不能更改。如果需要接口的新版本,必須創建一個全新的接口。如果創建的功能將在大范圍的全異對象間使用,則使用接口。抽象類應主要用于關系密切的對象,而接口最適合為不相關的類提供通用功能。 如果要設計小而簡練的功能塊,則使用接口。如果要設計大的功能單元,則使用抽象類。 如果要在組件的所有實現間提供通用的已實現功能,則使用抽象類。抽象類允許部分實現類,而接口不包含任何成員的實現。

           解釋:
          abstract classinterface是Java語言中對于抽象類定義進行支持的兩種機制,正是由于這兩種機制的存在,才賦予了Java強大的面向對象能力。abstract classinterface之間在對于抽象類定義的支持方面具有很大的相似性,甚至可以相互替換,因此很多開發者在進行抽象類定義時對于abstract class和interface的選擇顯得比較隨意。其實,兩者之間還是有很大的區別的,對于它們的選擇甚至反映出對于問題領域本質的理解、對于設計意圖的理解是否正確、合理。本文將對它們之間的區別進行一番剖析,試圖給開發者提供一個在二者之間進行選擇的依據。 

          理解抽象類 :

          abstract class和interface在Java語言中都是用來進行抽象類(本文中的抽象類并非從abstract class翻譯而來,它表示的是一個抽象體,而abstract class為Java語言中用于定義抽象類的一種方法,請讀者注意區分)定義的,那么什么是抽象類,使用抽象類能為我們帶來什么好處呢? 

          在面向對象的概念中,我們知道所有的對象都是通過類來描繪的,但是反過來卻不是這樣。并不是所有的類都是用來描繪對象的,如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。抽象類往往用來表征我們在對問題領域進行分析、設計中得出的抽象概念,是對一系列看上去不同,但是本質上相同的具體概念的抽象。比如:如果我們進行一個圖形編輯軟件的開發,就會發現問題領域存在著圓、三角形這樣一些具體概念,它們是不同的,但是它們又都屬于形狀這樣一個概念,形狀這個概念在問題領域是不存在的,它就是一個抽象概念。正是因為抽象的概念在問題領域沒有對應的具體概念,所以用以表征抽象概念的抽象類是不能夠實例化的。 

          在面向對象領域,抽象類主要用來進行類型隱藏。我們可以構造出一個固定的一組行為的抽象描述,但是這組行為卻能夠有任意個可能的具體實現方式。這個抽象描述就是抽象類,而這一組任意個可能的具體實現則表現為所有可能的派生類。模塊可以操作一個抽象體。由于模塊依賴于一個固定的抽象體,因此它可以是不允許修改的;同時,通過從這個抽象體派生,也可擴展此模塊的行為功能。熟悉OCP的讀者一定知道,為了能夠實現面向對象設計的一個最核心的原則OCP(Open-Closed Principle),抽象類是其中的關鍵所在。 


          從語法定義層面看abstract class和interface: 

          在語法層面,Java語言對于abstract class和interface給出了不同的定義方式,下面以定義一個名為Demo的抽象類為例來說明這種不同。 

          使用abstract class的方式定義Demo抽象類的方式如下: 

          abstract class Demo 
          { 
           abstract void method1(); 
           abstract void method2(); 
           ... 
          } 

          使用interface的方式定義Demo抽象類的方式如下: 

          interface Demo 

           void method1(); 
           void method2(); 
           ... 


          在abstract class方式中,Demo可以有自己的數據成員,也可以有非abstarct的成員方法,而在interface方式的實現中,Demo只能夠有靜態的不能被修改的數據成員(也就是必須是static final的,不過在interface中一般不定義數據成員),所有的成員方法都是abstract的。從某種意義上說,interface是一種特殊形式的abstract class。 

                從編程的角度來看,abstract class和interface都可以用來實現"design by contract"的思想。但是在具體的使用上面還是有一些區別的。 

          首先,abstract class在Java語言中表示的是一種繼承關系,一個類只能使用一次繼承關系。但是,一個類卻可以實現多個interface。也許,這是Java語言的設計者在考慮Java對于多重繼承的支持方面的一種折中考慮吧。 

          其次,在abstract class的定義中,我們可以賦予方法的默認行為。但是在interface的定義中,方法卻不能擁有默認行為,為了繞過這個限制,必須使用委托,但是這會 增加一些復雜性,有時會造成很大的麻煩。 

          在抽象類中不能定義默認行為還存在另一個比較嚴重的問題,那就是可能會造成維護上的麻煩。因為如果后來想修改類的界面(一般通過abstract class或者interface來表示)以適應新的情況(比如,添加新的方法或者給已用的方法中添加新的參數)時,就會非常的麻煩,可能要花費很多的時間(對于派生類很多的情況,尤為如此)。但是如果界面是通過abstract class來實現的,那么可能就只需要修改定義在abstract class中的默認行為就可以了。 

          同樣,如果不能在抽象類中定義默認行為,就會導致同樣的方法實現出現在該抽象類的每一個派生類中,違反了"one rule,one place"原則,造成代碼重復,同樣不利于以后的維護。因此,在abstract class和interface間進行選擇時要非常的小心。 


          從設計理念層面看abstract class和interface 

          上面主要從語法定義和編程的角度論述了abstract class和interface的區別,這些層面的區別是比較低層次的、非本質的。本小節將從另一個層面:abstract class和interface所反映出的設計理念,來分析一下二者的區別。作者認為,從這個層面進行分析才能理解二者概念的本質所在。 

          前面已經提到過,abstarct class在Java語言中體現了一種繼承關系,要想使得繼承關系合理,父類和派生類之間必須存在"is a"關系,即父類和派生類在概念本質上應該是相同的(參考文獻〔3〕中有關于"is a"關系的大篇幅深入的論述,有興趣的讀者可以參考)。對于interface 來說則不然,并不要求interface的實現者和interface定義在概念本質上是一致的,僅僅是實現了interface定義的契約而已。為了使論述便于理解,下面將通過一個簡單的實例進行說明。 

          考慮這樣一個例子,假設在我們的問題領域中有一個關于Door的抽象概念,該Door具有執行兩個動作open和close,此時我們可以通過abstract class或者interface來定義一個表示該抽象概念的類型,定義方式分別如下所示: 

          使用abstract class方式定義Door: 

          abstract class Door { 
           abstract void open(); 
           abstract void close(); 


            
          使用interface方式定義Door: 


          interface Door { 
           void open(); 
           void close(); 


            
          其他具體的Door類型可以extends使用abstract class方式定義的Door或者implements使用interface方式定義的Door。看起來好像使用abstract class和interface沒有大的區別。 

          如果現在要求Door還要具有報警的功能。我們該如何設計針對該例子的類結構呢(在本例中,主要是為了展示abstract class和interface反映在設計理念上的區別,其他方面無關的問題都做了簡化或者忽略)?下面將羅列出可能的解決方案,并從設計理念層面對這些不同的方案進行分析。 

          解決方案一: 

          簡單的在Door的定義中增加一個alarm方法,如下: 

          abstract class Door { 
           abstract void open(); 
           abstract void close(); 
           abstract void alarm(); 


            
          或者 

          interface Door { 
           void open(); 
           void close(); 
           void alarm(); 


            
          那么具有報警功能的AlarmDoor的定義方式如下: 

          class AlarmDoor extends Door { 
           void open() { ... } 
           void close() { ... } 
           void alarm() { ... } 


            
          或者 

          class AlarmDoor implements Door { 
           void open() { ... } 
           void close() { ... } 
           void alarm() { ... } 
          } 

          這種方法違反了面向對象設計中的一個核心原則ISP(Interface Segregation Priciple),在Door的定義中把Door概念本身固有的行為方法和另外一個概念"報警器"的行為方法混在了一起。這樣引起的一個問題是那些僅僅依賴于Door這個概念的模塊會因為"報警器"這個概念的改變(比如:修改alarm方法的參數)而改變,反之依然。 

          解決方案二: 

          既然open、close和alarm屬于兩個不同的概念,根據ISP原則應該把它們分別定義在代表這兩個概念的抽象類中。定義方式有:這兩個概念都使用abstract class方式定義;兩個概念都使用interface方式定義;一個概念使用abstract class方式定義,另一個概念使用interface方式定義。 

          顯然,由于Java語言不支持多重繼承,所以兩個概念都使用abstract class方式定義是不可行的。后面兩種方式都是可行的,但是對于它們的選擇卻反映出對于問題領域中的概念本質的理解、對于設計意圖的反映是否正確、合理。我們一一來分析、說明。 

          如果兩個概念都使用interface方式來定義,那么就反映出兩個問題:1、我們可能沒有理解清楚問題領域,AlarmDoor在概念本質上到底是Door還是報警器?2、如果我們對于問題領域的理解沒有問題,比如:我們通過對于問題領域的分析發現AlarmDoor在概念本質上和Door是一致的,那么我們在實現時就沒有能夠正確的揭示我們的設計意圖,因為在這兩個概念的定義上(均使用interface方式定義)反映不出上述含義。 

          如果我們對于問題領域的理解是:AlarmDoor在概念本質上是Door,同時它有具有報警的功能。我們該如何來設計、實現來明確的反映出我們的意思呢?前面已經說過,abstract class在Java語言中表示一種繼承關系,而繼承關系在本質上是"is a"關系。所以對于Door這個概念,我們應該使用abstarct class方式來定義。另外,AlarmDoor又具有報警功能,說明它又能夠完成報警概念中定義的行為,所以報警概念可以通過interface方式定義。如下所示: 

          abstract class Door { 
           abstract void open(); 
           abstract void close(); 

          interface Alarm { 
           void alarm(); 

          class AlarmDoor extends Door implements Alarm { 
           void open() { ... } 
           void close() { ... } 
              void alarm() { ... } 


            
          這種實現方式基本上能夠明確的反映出我們對于問題領域的理解,正確的揭示我們的設計意圖。其實abstract class表示的是"is a"關系,interface表示的是"like a"關系,大家在選擇時可以作為一個依據,當然這是建立在對問題領域的理解上的,比如:如果我們認為AlarmDoor在概念本質上是報警器,同時又具有Door的功能,那么上述的定義方式就要反過來了。 

          結論 

          abstract class和interface是Java語言中的兩種定義抽象類的方式,它們之間有很大的相似性。但是對于它們的選擇卻又往往反映出對于問題領域中的概念本質的理解、對于設計意圖的反映是否正確、合理,因為它們表現了概念間的不同的關系(雖然都能夠實現需求的功能)。     

           

           

          主站蜘蛛池模板: 鹤峰县| 白水县| 山阴县| 化州市| 海兴县| 商河县| 孝昌县| 岳西县| 龙口市| 绥化市| 汪清县| 同心县| 吴堡县| 孟津县| 庄河市| 盐山县| 怀集县| 肥乡县| 特克斯县| 克拉玛依市| 张家港市| 高清| 长沙县| 金湖县| 十堰市| 浙江省| 民县| 辰溪县| 岑巩县| 青铜峡市| 东丰县| 尚志市| 盘山县| 博客| 启东市| 黄骅市| 青河县| 开江县| 金乡县| 东海县| 丰原市|