設計繼承
2006 年 10 月 6 日
在面向對象圈中爭論最久的議題之一,就是 開放繼承 和設計繼承的辯論。設計繼承的原則,可能由 Josh Bloch 總結得最好:「設計和文件化用於繼承,否則禁止繼承」。採用這種方法,您必須小心決定哪些方法可以繼承,並 封閉 其他方法,以阻止它們被覆寫。
設計繼承最常見的論點是,由於繼承是一種非常親密的(且會破壞封裝的)關係,因此子類別很容易透過在呼叫方法時省略必要的行為,來有效地破壞其父類別。
許多開發人員,尤其是那些具有 啟用態度 的開發人員,會發現這種論點並無說服力。另一個我發現更有吸引力的論點,是 Elliote Rusty Harold 在討論 XOM 設計原則 時提出的。重點在於「API 是由專家為非專家編寫的」。程式庫撰寫者應精通程式庫所使用的技術。她應努力簡化此技術,供程式庫使用者使用。封裝的重點在於隱藏祕密,因此一個好的程式庫應隱藏所有種類的複雜性和危險點,讓程式庫使用者無法透過呼叫或繼承使用該程式庫。因此,使用 XOM,我可以安全地覆寫程式庫類別,以執行我想要執行的動作,但程式庫保證它仍會產生格式良好的 XML,而我無需擔心所有可能出錯的醜陋小細節。
這樣的論點對我來說比通常的論點更具說服力,而通常的論點隱含著程式庫撰寫者很聰明,而使用者很愚蠢。這不是關於能力,而是關於詳細的知識。我希望盡可能地忽略 XML 的骯髒細節。透過減輕我了解這些類型細節的需要,我可以將我的腦力用於我想完成的實際任務。
儘管有這個令人信服的論點,我的直覺,以及我具有啟發性的態度,傾向於偏好開放繼承。也許這個問題的關鍵在於我們用來標示繼承安全區域的機制。通常我們有的只是封閉類別和方法的能力。安撫兩方陣營的替代方案是具有克服封閉的能力。這樣一來,你必須想辦法覆寫未設計好的東西。如果你沒有明確開啟封閉,那麼編譯器只允許正常繼承,但如果你使用封閉開啟機制,那麼編譯器會將信任交給你,而你必須承擔後果。因此,我比較喜歡用「勸阻」取代 Josh Bloch 的「禁止」。
從更廣泛的角度來看,我猜想我們在思考介面時,無論是呼叫還是繼承,仍有很大的改進空間。像 消費者驅動合約 之類的想法是必要的,以幫助我們重新思考介面定義的意義。我不知道答案是什麼,但我認為一個好的答案會讓我們所有人感到驚訝。