2019年4月14日 星期日

繼承(Inheritance)與合成(Composition)

在 Design Pattern 的書裡,大概都會提到「多用合成、少用繼承」,不過具體來說到底繼承會產生什麼問題、合成又能解決什麼問題,一直到現在才有比較明確的感覺。但由於不太擅長描述這種有些抽象的問題,所以這裡就簡單地紀錄一些感覺到的重點,細節就請參閱底下的參考資料吧 XD。

首先,一切的源頭都是為了 OCP(Open-Closed Principle),也就是要盡可能滿足「對擴充開放、對修改封閉」這樣的準則。不過要滿足這個準則,其實會讓程式碼變得複雜,所以在選擇的過程也必須謹慎小心,盡可能只在真正需要的地方去滿足,而不要把這個準則套用到整個系統的每個角落 [1]。

在考量 OCP 的前提之下,由於繼承是屬於在編譯期間的關聯,因此很容易會導致使用繼承時,擴充會需要修改既有的程式碼。這就會導致違反了 OCP 當中的「對修改封閉」的要件。

另外繼承在可能性眾多的情況,也很容易導致子類別的數量爆炸,造成日後維護的困難。

反過來說,合成是屬於在執行期間的關聯,因此較有機會可以避免上述的問題。不過依據狀況的不同,合成也有可能形成子類別較多的現象,雖然不至於到數量爆炸的程度,但往往也會使得 API 變得難以掌握。這類的問題就得複合多種 Design Pattern 來隱藏問題,讓呼叫者不需要對細節有太多的了解。

不過同時也需要注意的是,雖然說概念上提到「少用繼承」,但使用合成其實並不表示完全不使用繼承。關鍵在於「不繼承行為」,但合成常常會需要「繼承型別」(然而這或許只限定在像是 Java 這類強型別的語言上)。

參考資料
  1. 深入淺出設計模式
  2. 物件導向程式設計:為何說composition優於inheritance?
  3. 請問,為什麼要『多用合成,少用繼承』? (java程式語言)
  4. 省思物件導向設計 第2回- 物件導向設計方法面臨的問題 

沒有留言: