繼承旨在複用父類實現,無需了解細節即可獲得所需特徵。然而,子類往往只需父類部分特徵,繼承卻強制攜帶所有特徵——包括不需要甚至極力避免的特徵。在支援多重繼承的語言中,這極易引發難以發現的錯誤。物件導向語言因此衍生出各種限制機制(如 final、private、存取修飾符)來約束子類對父類成員的使用。
假設主人希望狗會爬低矮的樹,但不希望它像猴子能倒掛樹尾、飛簷走壁。若讓狗繼承猴子,將獲得所有猴子特徵,違背原始意圖。這正是繼承「過度給予」的弊端。
設計模式強調面向介面編程。猴子擁有「爬樹」與「尾巴倒掛」兩個介面。主人只需狗實作「爬樹」介面,即可獲得目標能力,完全避開「尾巴倒掛」副作用。介面定義「能做什麼」,而非「是什麼」,實現精準能力賦予。
OO 技術發展多年,明顯趨勢是繼承使用減少,介面使用普及。對比 JDK 早期類庫(大量繼承層級)與新增類庫(幾乎全面採用介面),可清晰感知編程風格演變。介面非繼承替代品,而是互補:當關注行為能力而非具體實現類型時,介面提供極致靈活性。
// 介面定義
interface Climable { void climb(); }
interface Bitable { void bite(); }
// 具體實現
class Dog implements Climable, Bitable { ... }
class Monkey implements Climable { ... }
class Cat implements Climable, Bitable { ... }
// 使用端:只關注能力,不關注具體類型
Climable climber = getClimber(); // 可能是 Dog、Monkey 或 Cat
climber.climb();
// 組合能力需求
ClimableAndBitable hunter = getHunter(); // 實作雙介面
hunter.climb();
hunter.bite();
// 運維期替換實現:發現貓更靈活,直接替換 Dog 為 Cat,調用碼零修改
從繼承走向介面,是軟體設計從「實現復用」向「契約導向」成熟的標誌。現代框架(Spring、Dubbo 等)皆以介面為核心,構建可擴展、可替換的企業級架構。