接口與抽象類

    接口(interface)與抽象類(abstract class)的區別是我在面試的時候幾乎必問的一個問題,可惜很少有面試者能回答得很好。大多數能說出它們的特性,比如不能實例化,是定義接口的用途等等。但是在實際工作環境中能把這兩個運用得很好的並不多。在實際工作中很多.NET程序員會有意識的使用接口,但是很少使用抽象類。C++程序員,由於受到語言的限制(語言本身並沒有定義接口這個概念),只會將抽象類定義成一組具體類的基類(base class),並且這麼做也只是爲了以後的動態綁定。

   我個人認爲C#,Java在語言層面分離出接口和抽象類是很明智的。這使得兩者之間的關係更清晰,職責更明確。我相信接口是很容易理解的:接口定義了一組行爲。也就是說,任意類,如果繼承了該接口,就擁有這一組行爲,但是如何實現該行爲,接口並沒有指出,如何實現是由繼承類關心的。這個關係和工作中老闆和員工的關係很像。老闆只需要指明工作方向(定義行爲),具體的活交由手下員工去做(實現行爲)。通常在實現一個簡單的功能時,我們首先會想到這麼去設計類之間的關係。這種簡單的具體類(concrete class)繼承接口(interface)關係,在邏輯不太複雜的情況下,會工作得很好(如圖1左)。 然而隨着需求的不斷變化,功能也會越來越複雜。具體類所做得事也變得越來越多:Work() 函數中需要Validate(), Read(), Write()以及Display()。在編程中我們一直強調一個函數只做一件事,類的功能要單一。可是對於日趨複雜的業務邏輯,我們如何能夠做到這點呢?繼續抽象。將公共部分抽象出來形成一個新的類(如圖1右)。

Common1繼承於Interface1,所以它必定要實現Work行爲。Common1不急於馬上實現這個行爲。它將這個行爲繼續分解:

     public void Work()

     {

               if (Validate() == true)

               {

                        Read();

                        Write();

                        Display("Succeed");

               }

               else

               {

                       Display("fail");

               }

     }

這樣Work的邏輯就變得非常清晰了。假如在這個例子中,所有的具體類驗證(Validate)和顯示(Display)功能的邏輯都是一樣的,那麼Validate()和Display()接可以直接在Common1類中實現。對於Read和Write,不同的具體類會有不同的實現。所以Common1可以將其定義爲抽象函數。這樣Common1就自然而然的成爲了抽象類。我還是拿剛纔的老闆員工例子來解釋:當一個老闆手下員工做得事越來越雜,員工也越來越多,以至於他們都不知道邏輯到底該是什麼的時候(老闆的指示太heigh level了),這時就有必要再請一個小組長:小組長能夠理解老闆的最高指示,並將其分解成若干小問題,然後將其下派到自己的組員。實際上小組長也並沒有做具體的事(不能實例化),但是他將事情細化了,使得手下能夠明確知道該做什麼(一個函數只做一件事)。

      在我的項目中這種接口和抽象類的關係被大量使用,接口類定義行爲,抽象類定義模板(template pattern),具體類實現具體細化後的行爲。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章