Effective Java 3e - Item 19: Design and document for inheritance or else prohibit it 繼承的設計與文件說明或禁止繼承 筆記。
設計用來被繼承的類別(a class designed for inheritance)(以下簡稱「被繼承類別」)時的注意事項。
如果被繼承類別中有引用自身(self-use)的可覆寫方法(overridable methods)必須在文件特別說明,例如利用javadoc的@implSpec
註解。
設計被繼承類別時要慎選可覆寫方法,可覆寫方法越少越好。
撰寫子類別來測試被繼承類別。
被繼承類別的建構式中不應呼叫可覆寫的方法,也就是建構式中不應呼叫public
及protected
方法,因為都能被子類別覆寫。
例如下面Super
類別的建構式中呼叫自身的method1
、method2
、method3
方法,若子類覆寫了這三個方法,子類初始化時父類建構式會先執行,在呼叫這三個方法時會變成呼叫成子類的實作而出錯。
public class Super {
public Super() {
method1(); // 不應在建構式呼叫自身的public方法
method2(); // 不應在建構式呼叫自身的protected方法
method3(); // 不應在建構式呼叫自身的default(無存取修飾)方法
method4(); // 允許在建構式呼叫自身的private方法
}
public void method1() { ... } // overridable
protected void method2() { ... } // overridable
void method3() { ... } // overridable
private void method4() { ... } // 無法被覆寫
}
若類別實作Cloneable
及Serializable
介面,則子類別繼承時必須注意。clone()
及readObject()
方法中不可直接或間接呼叫可覆寫方法。
若被繼承類別實作Serializable
且實作了readResolve()
或writeReplace()
方法,則此二方法應為protected
而非private
,否則子類在序列化及反序列化時此兩方法會被忽略。
若類別非設計用來被繼承,且沒有繼承注意事項的文件說明,則此類別應該禁止被繼承。
避免類別被繼承的做法一是宣告類別為final
。
public final class ProhibitExtensionClass { // final類別無法繼承
public ProhibitExtensionClass() {
}
}
避免類別被繼承的做法二為建構式改為private
或package-private(無修飾子)並以靜態工廠方法來產生實例。
public class ProhibitExtensionClass {
private ProhibitExtensionClass() { // 子類別建構式中無法super(),因此無法繼承
}
public static ProhibitExtensionClass createInstance() { // 靜態工廠方法
return new ProhibitExtensionClass();
}
}
避免被繼承類使用自身覆寫方法(self-use overiddable method)的設計。
總之設計一個要被繼承的類別是困難的,否則建議使用組合設計替代繼承。
參考:
沒有留言:
張貼留言