Cat 類有 Scratch(),派生 ScratchlessCat 覆蓋為空。書中建議:在 Cat 中引入 Claw 組件,Cat 包含 Claw,有爪子才能抓。
作者意在說明:繼承表達「是一種」關係,若子類行為與父類根本衝突(如貓不抓),說明父類假設過強(所有貓都能抓)。正確建模應將可變行為抽離為組件(Claw),父類持有組件引用,行為委托給組件。
// 繼承方式(脆弱)
class Cat { void scratch() { ... } }
class ScratchlessCat extends Cat { void scratch() {} } // 空實現,違反里氏替換原則
// 組合方式(靈活)
interface Claw { void scratch(); }
class RealClaw implements Claw { void scratch() { ... } }
class NoClaw implements Claw { void scratch() {} } // 空實現隔離在組件
class Cat { Claw claw; Cat(Claw c) { this.claw = c; } void scratch() { claw.scratch(); } }
// 使用
Cat normal = new Cat(new RealClaw());
Cat noScratch = new Cat(new NoClaw());
onCreate() 默認空實現),不一定是錯誤。UnsupportedOperationException 或用組合建模能力差異。