1. 程式人生 > >面向物件之繼承與組合

面向物件之繼承與組合

      

 最近一個師弟問某實現是該用物件持有(其實就是組合)還是整合關係實現好。所以就在這裡簡單的淺談一下,僅是個人觀點,僅供參考。如果寫的不對的地方請指出。

     首先它們都是實現系統功能重用,程式碼複用的最常用的有效的設計技巧,都是在設計模式中的基礎結構。相信大家已瞭解的,類繼承允許我們根據自己的實現來覆蓋重寫父類的實現細節,父類的實現對於子類是可見的,所以我們一般稱之為白盒複用。物件持有(其實就是組合)要求建立一個號的介面,但是整體類和部分類之間不會去關心各自的實現細節,即它們之間的實現細節是不可見的,故成為黑盒複用。

     繼承是在編譯時刻靜態定義的,即是靜態複用,在編譯後子類和父類的關係就已經確定了。而組合這是運用於複雜的設計,它們之間的關係是在執行時候才確定的,即在對物件沒有建立執行前,整體類是不會知道自己將持有特定介面下的那個實現類。在擴充套件方面組合比整合更具有廣泛性。

    繼承中父類定義了子類的部分實現,而子類中又會重寫這些實現,修改父類的實現,設計模式中認為這是一種破壞了父類的封裝性的表現。這個結構導致結果是父類實現的任何變化,必然導致子類的改變。然而組合這不會出現這種現象。

    物件的組合還有一個優點就是有助於保持每個類被封裝,並被集中在單個任務上(類設計的單一原則)。這樣類的層次結構不會擴大,一般不會出現不可控的龐然大類。而累的繼承就可能出來這些問題,所以一般編碼規範都要求類的層次結構不要超過3層。組合是大型系統軟體實現即插即用時的首選方式。

   在設計模式中這兩個概念同時出現的地方就是Adapter模式:物件適配(組合)和類適配(繼承)。一般我們提倡用物件適配而不是類適配。基於上面的原因。還有就是在我們的Java和.NET這些完全面向物件的語言而言類的繼承是單繼承,取消了C++等的多繼承。下面放兩個這兩種方式的UML圖:

類適配圖:

 

    clip_image002

物件適配圖:

clip_image002[9]

 

     最後還說一句,“優先使用物件組合,而不是繼承”是面向物件設計的第二原則。但並不是說什麼都設計都用組合,只是優先考慮組合,更不是說繼承即使不好的設計,應該用組合,應為他們之間也有各自的優勢。下面是他們之間的優缺點比比較表:

組 合 關 系

繼 承 關 系

優點:不破壞封裝,整體類與區域性類之間鬆耦合,彼此相對獨立

缺點:破壞封裝,子類與父類之間緊密耦合,子類依賴於父類的實現,子類缺乏獨立性

優點:具有較好的可擴充套件性

缺點:支援擴充套件,但是往往以增加系統結構的複雜度為代價

優點:支援動態組合。在執行時,整體物件可以選擇不同型別的區域性物件

缺點:不支援動態繼承。在執行時,子類無法選擇不同的父類

優點:整體類可以對區域性類進行包裝,封裝區域性類的介面,提供新的介面

缺點:子類不能改變父類的介面

缺點:整體類不能自動獲得和區域性類同樣的介面

優點:子類能自動繼承父類的介面

缺點:建立整體類的物件時,需要建立所有區域性類的物件

優點:建立子類的物件時,無須建立父類的物件