302班

          java突擊隊(duì)
          posts - 151, comments - 74, trackbacks - 0, articles - 14
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          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有什么區(qū)別?

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

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

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

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

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

          如果預(yù)計(jì)要?jiǎng)?chuàng)建組件的多個(gè)版本,則創(chuàng)建抽象類。抽象類提供簡(jiǎn)單易行的方法來控制組件版本。通過更新基類,所有繼承類都隨更改自動(dòng)更新。另一方面,接口一旦創(chuàng)建就不能更改。如果需要接口的新版本,必須創(chuàng)建一個(gè)全新的接口。

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

           解釋:
          abstract classinterface是Java語言中對(duì)于抽象類定義進(jìn)行支持的兩種機(jī)制,正是由于這兩種機(jī)制的存在,才賦予了Java強(qiáng)大的面向?qū)ο竽芰Α?font color=#0000ff>abstract class和interface之間在對(duì)于抽象類定義的支持方面具有很大的相似性,甚至可以相互替換,因此很多開發(fā)者在進(jìn)行抽象類定義時(shí)對(duì)于abstract class和interface的選擇顯得比較隨意。其實(shí),兩者之間還是有很大的區(qū)別的,對(duì)于它們的選擇甚至反映出對(duì)于問題領(lǐng)域本質(zhì)的理解、對(duì)于設(shè)計(jì)意圖的理解是否正確、合理。本文將對(duì)它們之間的區(qū)別進(jìn)行一番剖析,試圖給開發(fā)者提供一個(gè)在二者之間進(jìn)行選擇的依據(jù)。 

          理解抽象類 :

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

          在面向?qū)ο蟮母拍钪校覀冎浪械膶?duì)象都是通過類來描繪的,但是反過來卻不是這樣。并不是所有的類都是用來描繪對(duì)象的,如果一個(gè)類中沒有包含足夠的信息來描繪一個(gè)具體的對(duì)象,這樣的類就是抽象類。抽象類往往用來表征我們?cè)趯?duì)問題領(lǐng)域進(jìn)行分析、設(shè)計(jì)中得出的抽象概念,是對(duì)一系列看上去不同,但是本質(zhì)上相同的具體概念的抽象。比如:如果我們進(jìn)行一個(gè)圖形編輯軟件的開發(fā),就會(huì)發(fā)現(xiàn)問題領(lǐng)域存在著圓、三角形這樣一些具體概念,它們是不同的,但是它們又都屬于形狀這樣一個(gè)概念,形狀這個(gè)概念在問題領(lǐng)域是不存在的,它就是一個(gè)抽象概念。正是因?yàn)槌橄蟮母拍钤趩栴}領(lǐng)域沒有對(duì)應(yīng)的具體概念,所以用以表征抽象概念的抽象類是不能夠?qū)嵗摹?nbsp;

          在面向?qū)ο箢I(lǐng)域,抽象類主要用來進(jìn)行類型隱藏。我們可以構(gòu)造出一個(gè)固定的一組行為的抽象描述,但是這組行為卻能夠有任意個(gè)可能的具體實(shí)現(xiàn)方式。這個(gè)抽象描述就是抽象類,而這一組任意個(gè)可能的具體實(shí)現(xiàn)則表現(xiàn)為所有可能的派生類。模塊可以操作一個(gè)抽象體。由于模塊依賴于一個(gè)固定的抽象體,因此它可以是不允許修改的;同時(shí),通過從這個(gè)抽象體派生,也可擴(kuò)展此模塊的行為功能。熟悉OCP的讀者一定知道,為了能夠?qū)崿F(xiàn)面向?qū)ο笤O(shè)計(jì)的一個(gè)最核心的原則OCP(Open-Closed Principle),抽象類是其中的關(guān)鍵所在。 


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

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

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

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

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

          interface Demo 

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


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

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

          首先,abstract class在Java語言中表示的是一種繼承關(guān)系,一個(gè)類只能使用一次繼承關(guān)系。但是,一個(gè)類卻可以實(shí)現(xiàn)多個(gè)interface。也許,這是Java語言的設(shè)計(jì)者在考慮Java對(duì)于多重繼承的支持方面的一種折中考慮吧。 

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

          在抽象類中不能定義默認(rèn)行為還存在另一個(gè)比較嚴(yán)重的問題,那就是可能會(huì)造成維護(hù)上的麻煩。因?yàn)槿绻髞硐胄薷念惖慕缑妫ㄒ话阃ㄟ^abstract class或者interface來表示)以適應(yīng)新的情況(比如,添加新的方法或者給已用的方法中添加新的參數(shù))時(shí),就會(huì)非常的麻煩,可能要花費(fèi)很多的時(shí)間(對(duì)于派生類很多的情況,尤為如此)。但是如果界面是通過abstract class來實(shí)現(xiàn)的,那么可能就只需要修改定義在abstract class中的默認(rèn)行為就可以了。 

          同樣,如果不能在抽象類中定義默認(rèn)行為,就會(huì)導(dǎo)致同樣的方法實(shí)現(xiàn)出現(xiàn)在該抽象類的每一個(gè)派生類中,違反了"one rule,one place"原則,造成代碼重復(fù),同樣不利于以后的維護(hù)。因此,在abstract class和interface間進(jìn)行選擇時(shí)要非常的小心。 


          從設(shè)計(jì)理念層面看abstract class和interface 

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

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

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

          使用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??雌饋砗孟袷褂胊bstract class和interface沒有大的區(qū)別。 

          如果現(xiàn)在要求Door還要具有報(bào)警的功能。我們?cè)撊绾卧O(shè)計(jì)針對(duì)該例子的類結(jié)構(gòu)呢(在本例中,主要是為了展示abstract class和interface反映在設(shè)計(jì)理念上的區(qū)別,其他方面無關(guān)的問題都做了簡(jiǎn)化或者忽略)?下面將羅列出可能的解決方案,并從設(shè)計(jì)理念層面對(duì)這些不同的方案進(jìn)行分析。 

          解決方案一: 

          簡(jiǎn)單的在Door的定義中增加一個(gè)alarm方法,如下: 

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


            
          或者 

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


            
          那么具有報(bào)警功能的AlarmDoor的定義方式如下: 

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


            
          或者 

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

          這種方法違反了面向?qū)ο笤O(shè)計(jì)中的一個(gè)核心原則ISP(Interface Segregation Priciple),在Door的定義中把Door概念本身固有的行為方法和另外一個(gè)概念"報(bào)警器"的行為方法混在了一起。這樣引起的一個(gè)問題是那些僅僅依賴于Door這個(gè)概念的模塊會(huì)因?yàn)?報(bào)警器"這個(gè)概念的改變(比如:修改alarm方法的參數(shù))而改變,反之依然。 

          解決方案二: 

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

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

          如果兩個(gè)概念都使用interface方式來定義,那么就反映出兩個(gè)問題:1、我們可能沒有理解清楚問題領(lǐng)域,AlarmDoor在概念本質(zhì)上到底是Door還是報(bào)警器?2、如果我們對(duì)于問題領(lǐng)域的理解沒有問題,比如:我們通過對(duì)于問題領(lǐng)域的分析發(fā)現(xiàn)AlarmDoor在概念本質(zhì)上和Door是一致的,那么我們?cè)趯?shí)現(xiàn)時(shí)就沒有能夠正確的揭示我們的設(shè)計(jì)意圖,因?yàn)樵谶@兩個(gè)概念的定義上(均使用interface方式定義)反映不出上述含義。 

          如果我們對(duì)于問題領(lǐng)域的理解是:AlarmDoor在概念本質(zhì)上是Door,同時(shí)它有具有報(bào)警的功能。我們?cè)撊绾蝸碓O(shè)計(jì)、實(shí)現(xiàn)來明確的反映出我們的意思呢?前面已經(jīng)說過,abstract class在Java語言中表示一種繼承關(guān)系,而繼承關(guān)系在本質(zhì)上是"is a"關(guān)系。所以對(duì)于Door這個(gè)概念,我們應(yīng)該使用abstarct class方式來定義。另外,AlarmDoor又具有報(bào)警功能,說明它又能夠完成報(bào)警概念中定義的行為,所以報(bào)警概念可以通過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() { ... } 


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

          結(jié)論 

          abstract class和interface是Java語言中的兩種定義抽象類的方式,它們之間有很大的相似性。但是對(duì)于它們的選擇卻又往往反映出對(duì)于問題領(lǐng)域中的概念本質(zhì)的理解、對(duì)于設(shè)計(jì)意圖的反映是否正確、合理,因?yàn)樗鼈儽憩F(xiàn)了概念間的不同的關(guān)系(雖然都能夠?qū)崿F(xiàn)需求的功能)。     

           

           

          主站蜘蛛池模板: 伊金霍洛旗| 桂阳县| 济宁市| 龙游县| 清河县| 邢台县| 稷山县| 靖州| 芦山县| 金阳县| 乐昌市| 富锦市| 邯郸县| 洪雅县| 自治县| 呼和浩特市| 宝清县| 麻江县| 垣曲县| 新泰市| 三原县| 翁牛特旗| 仪陇县| 区。| 宁国市| 新丰县| 梧州市| 米脂县| 弥勒县| 留坝县| 玉门市| 盐池县| 吴忠市| 昌宁县| 南郑县| 武汉市| 舒城县| 土默特右旗| 介休市| 昌宁县| 桦南县|