從面向對象設計談接口和抽象類的異同

java和c#都不支持類的多繼承,相對c++來說,又都增加了接口的概念,一個類可以實現多個接口;和c++一樣,java和c#保留了抽象類的概念。在編碼中很多情況下接口和抽象類可以互換,並且都能正確編譯和運行,GOF23種設計模式在不同的書籍上也出現了接口和抽象類混用的情況。從語言層面講,把接口看成是僅包含抽象屬性和抽象方法的抽象類,勉強可以說得過去。所以很多程序員分不清什麼時候該用接口,什麼時候該用抽象類,只好任選其一。

    首先,java和c#不支持類的多繼承是很有道理的(類的單一職責原則),當你在設計時遇到必須用多繼承的情景時,請檢查你的類結構設計是否合理,或者把某些父類改成接口。

    其次,接口中聲明的成員方法不能有任何實現,這樣如果兩個類實現這個接口,有可能兩個類需要編寫同樣的實現。而用抽象類則可以把實現寫在抽象的父類中。

    以上兩點僅僅是語言層面上的區別,是顯而易見的。如果做到良好的面向對象設計,把類和類關係定的合理,可能根本遇不到上述兩種情況。我們來看一個場景:

    固定翼飛機、軍用固定翼飛機、民用固定翼飛機(民航客機)、孫悟空、海鷗

    軍用固定翼飛機、民用固定翼飛機,都屬於固定翼飛機,有強烈的 is a 關係,所以應該從固定翼飛機繼承;如果一架飛機是固定翼飛機,那麼它不可能僅僅是固定翼飛機,因爲它不是民用就是軍用,所以固定翼飛機是抽象的,不會有它本身的實例,有的只是它子類的實例。所以固定翼飛機是 abstract class 。

    上述五類事物都會飛,但顯然,飛機、鳥、會飛的人完全不是一回事,不應該讓它們繼承於一個抽象的AbstractFly類,所以固定翼飛機、孫悟空、海鷗都可以實現IFly接口,卻不能從同一個抽象類繼承。孫悟空實現了IFly接口,同時還可以和豬八戒等實現IChangeSelf(會變)接口。

    一個類可以實現多個接口,接口是沒有實際意義的,所以即使一個類實現了再多接口,它還可以不違反類的單一職責原則。反之,繼承於多個抽象類,大多會違反類的單一職責原則,要不然就是那幾個抽象類設計的不合理。

    另外,根據依賴倒置原則,當高層模塊和底層模塊不得不耦合時,最好由高層模塊定義一個“規範”,讓低層模塊來實現,而不是高層模塊直接調用低層模塊的類和成員方法。“規範”在很多時候用接口和抽象類都可以編譯和運行,但通過前文的例子,我們很容易知道這時應該用接口,因爲高層模塊僅僅是定義了一個規範,沒有實際意義,而且高層模塊並不瞭解低層模塊的類結構,不該強行爲低層模塊設置父類,影響低層模塊實現的靈活性。

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