繼承已經是一個古老的話題了,不過最近又在一些地方看到有人討論它,加上自己也有一些想法,因 此形成了這篇文章。
繼承好不好?
經典的OO理論說:繼承是面向對象的三大基石之一。
現代的OO理論說:組合優於繼承。
這兩種說法顯然是彼此沖突的。如果組合優於繼承的 話,那麼為什麼組合沒有取代繼承成為OO的基石呢?哪一種說法更有道理?
對這個問題,簡單的 說哪個比哪個更好其實是沒有多大意義的。我們應當從技術發展的歷史角度去看,這兩種說法各自是在 什麼時期產生的,它們形成的背景是什麼,才能對此問題有一個更加深刻的理解。
面向對象的思 想形成與上個世紀70年代,但真正在軟件開發陣營中流行開則是在80年代末和90年代初的時間。巧合的 是,這一時間也正是以Windows 3.x為代表的圖形操作系統興起的時代。於是面向對象當時所面臨的主要 問題就是:如何以OO的理論封裝圖形界面的開發?很多重要的早期OO思想都是在這個時期形成的,包括 對於繼承的使用。
讓我們考慮一下圖形界面的特點。很容易發現:這個領域確實非常適合使用繼 承,因為圖形對象天生就存在著is-a關系。比如,所有圖像對象都是Window,所有對話框都是Dialog, 所有按鈕都是Button,等等。所以我們可以看到的結果就是:所有的圖形界面框架都大量使用了繼承, 而且繼承的層次通常都非常深。例如,下圖是WPF中最主要的界面類——Window的繼承關系, 它的繼承層次深達9層!
所 有圖形框架在繼承方面幾乎無一例外。Java Swing對圖形框架由於較多使用MVC,因此繼承的深度要淺一 些,但是主要的JFrame類繼承深度也達到了6層:
至此我們應該理解,為什麼早期OO理論要將繼承作為面向對象的基石了。因為當時軟件開發的領域還比 較狹窄,所以很多開發者根據自己在圖形領域的開發經驗認定:繼承是OO必不可少的重要基礎,並且應 當盡可能的使用。
隨著歷史的發展,軟件開發逐漸進入了兩層和三層時代。程序員發現,原來在 桌面應用中得心應手的繼承突然之間不那麼好用了。為什麼呢?
原因之一:兩層和三層開發的主 要工作之一是對實體建模。而現實中的實體大多數是相對獨立的,它們之間的關系更多的表現為實體之 間的關聯,而不是從屬關系;
原因之二,很重要的現實問題:多層開發的主要物質基礎之一 ——關系數據庫,無法很自然的描述繼承關系。事實上這也是ORM出現的重要理由之一。但即 使是現在最好的ORM工具,要在數據庫中描述繼承關系仍然非常復雜。這迫使程序員在相當程度上放棄了 繼承;
原因之三:分層的開發方式逐漸流行開來,而繼承造成的類屬關系耦合非常不利於分層。
出於這些考慮,現代的OO理論為什麼更加推薦組合而非繼承,應該就容易理解了。
那麼 現代OO理論是不是對於繼承的看法就完美了呢?我認為也不是。事實上我認為,現代OO理論存在著忽視 繼承的問題,很多理論書籍只是簡單的告訴我們優先使用組合,而根本就不告訴我們在什麼時候應當合 理使用繼承,什麼時候不應當使用。這是從早期OO的過度使用繼承跳到了另一個極端,也是不可取的。