繼承!OO中程式再利用大幅提昇的小幫手。為了避免重複開發造成的成本浪費及日後難以維護等問題,於OO中通常採用繼承的方式來再利用父類別已經定義好的屬性跟方法(在C++成為運作)。但需切記適度的繼承是好的撰寫習慣,若過渡濫用反而會招致許多不必要的問題產生喔。
善用繼承。我想只要有OO基礎的人,對繼承一定不陌生。舉例而言:設計師定義了person這個類別,並將該有的屬性跟方法都以辛苦的建立完畢,突然發現系統中要加入一個superman的角色。此時,傳統程式必須要用copy或重新撰寫superman的所有相關變數跟方法,但試想超人除了會飛之外,其他幾乎跟人完全無異,那從頭到尾重寫一次的意義何在?我想繼承的概念就是由此衍生出來,現實世界中superman其實就是person的special case(在OO稱威specialization:特殊化),既然如此那就直接將父類別的相關資訊予以繼承到子類別,避免重複開發的問題產生,這樣superman的類別就只要多加一個fly()的方法就可以囉(ya…勝利手勢)。
Be careful!水可載舟亦可覆舟。過渡爛用繼承將造成維護時的苦難記!繼承是想反應出真實世界的主從跟類別之間的階層性(例如:動物是人的父類別)。但也不可將繼承無限上綱,我們都知道繼承的好,卻常忽略了他的缺點。試想在撰寫程式的過程中如果一路的將class從A被B繼承、B被C繼承、…如此循環下去到Z類別,當Z抬頭一看…哇他的父類別階層還真壯觀耶。當系統進入維護階段時,想必維護工程師打開class Z時,其內部程式碼可能用到父類別的資訊,換句話說Z調用的屬性跟方法有可能散佈在A~Y類別之間,換做是我應該會很想…『躺平』~
多重繼承給予充分的彈性,相對給予不少陷阱。多重繼承(Multiple Inheritance)顧名思義就是一個類別可以繼承多個父類別,他的存在使得用OO再描述現實世界能更加輕易且直觀,但也帶來下列兩個小陷阱:
- ambiguous calling(模糊呼叫):舉例而言,當C繼承了A跟B兩個類別,在A、B中皆有一個方法叫做method1(),由於A、B兩者是獨立的兩個類別當然沒有問題,但當C同時繼承了A跟B,並且我們試圖透過C來呼叫method1()時…恭喜~the problem is coming,試問現在C呼叫的method1()到底是呼叫class A或class B的method1()勒!
- 重複繼承:在繼承中當B繼承A,於系統的核心運作其實產生B物件時會順便將A物件產生出來以利B物件能使用之。噹噹!問題來囉~想像一個情境:C、B繼承A,又D繼承了C、B,此時產生D的時候,由於C跟B當中皆有一份A,所以D將會擁有兩份A的複製,造成了多餘且無謂的重複繼承現象產生。
單一繼承+介面 = 多重繼承可能引發問題的解決方案。在java中只允許單一繼承所以不會有多重繼承帶來的缺點。一樣有利即有弊,他將失去多重繼承龐大的彈性。為了補足上述問題,java中提供了介面(interface)來模擬出多重繼承的效果。如果既可達到多重繼承的效果、又可檢少引發的問題點,這寫是java為何能在OO當中的地位屹立不搖的原因囉。
從design pattern中給予的忠告:為了系統日後的維護彈性,請『善用合成、少用繼承』。至於合成的概念,後續在聊囉~~