3. 父類引用子類
這是說一個父類保存了其子類的引用,返回具體的其子類類型,以具體的其子類類型做為方法的參數,或者在方法中以本地變量的方式使用、初始化了具體的其子類實例。一句話,父類的任何地方都不應該出現“以其子類型”定義的靜態變量、實例變量和本地變量(Local variables)。
組合關系
父類組合(Composite)其子類的關系不能存在,因為這會導致運行時刻的遞歸初始化,產生StackOverflow錯誤,代碼如下:
public class Base {
Derived d = new Derived();
// 或者在構造方法中調用new Derived();
public Base() {
d = new Derived();
}
}
public class Derived extends Base {
}
只要存在父類組合其子類的關系,即要在父類初始化時刻同時初始化其子類,必定導致這樣的問題,無論是在定義實例變量的時候初始化,還是在構造器中初始化。當然,即使實例變量定義為父類,如果實際初始化的是其子類,也會產生同樣的錯誤。
聚合關系
父類聚合(Aggregate)其子類的關系也不應該存在。聚合關系和組合關系的不同就在于初始化過程,在聚合關系中,其子類的初始化不在父類初始化過程中,這不會導致遞歸問題。但這并不是說這樣做就是好的。
直接以其子類型定義靜態變量、實例變量,等于把抽象的父類綁定到了具體的子類型。這是對“繼承關系是一種抽象關系”的破壞,它使更抽象的父類不再具有抽象的涵義。
在父類方法的實現中,以其子類型定義本地變量,和父類聚合其子類“效果”是一樣的。
以父類型或者更抽象的類型來定義變量
在父類中,可以使用父類型或者更抽象的類型來定義變量。雖然不是一種很好的實踐,但有時的確需要把其子類型的實例付值給這些變量。一般情況下,這樣做的時候會選擇動態加載子類的實例:
public abstract class Factory {
private static Factory instance;
public synchronized static Factory getInstance() {
// 從配置文件中讀取子類型名稱
String factoryName = readFromConfig();
instance = Class.forName(factoryName).newInstance();
....
}
public Object createSomething();
}
即使如此,我個人的看法是,盡可能避免使用子類的實例。
這是說一個父類保存了其子類的引用,返回具體的其子類類型,以具體的其子類類型做為方法的參數,或者在方法中以本地變量的方式使用、初始化了具體的其子類實例。一句話,父類的任何地方都不應該出現“以其子類型”定義的靜態變量、實例變量和本地變量(Local variables)。
組合關系
父類組合(Composite)其子類的關系不能存在,因為這會導致運行時刻的遞歸初始化,產生StackOverflow錯誤,代碼如下:
public class Base {
Derived d = new Derived();
// 或者在構造方法中調用new Derived();
public Base() {
d = new Derived();
}
}
public class Derived extends Base {
}
只要存在父類組合其子類的關系,即要在父類初始化時刻同時初始化其子類,必定導致這樣的問題,無論是在定義實例變量的時候初始化,還是在構造器中初始化。當然,即使實例變量定義為父類,如果實際初始化的是其子類,也會產生同樣的錯誤。
聚合關系
父類聚合(Aggregate)其子類的關系也不應該存在。聚合關系和組合關系的不同就在于初始化過程,在聚合關系中,其子類的初始化不在父類初始化過程中,這不會導致遞歸問題。但這并不是說這樣做就是好的。
直接以其子類型定義靜態變量、實例變量,等于把抽象的父類綁定到了具體的子類型。這是對“繼承關系是一種抽象關系”的破壞,它使更抽象的父類不再具有抽象的涵義。
在父類方法的實現中,以其子類型定義本地變量,和父類聚合其子類“效果”是一樣的。
以父類型或者更抽象的類型來定義變量
在父類中,可以使用父類型或者更抽象的類型來定義變量。雖然不是一種很好的實踐,但有時的確需要把其子類型的實例付值給這些變量。一般情況下,這樣做的時候會選擇動態加載子類的實例:
public abstract class Factory {
private static Factory instance;
public synchronized static Factory getInstance() {
// 從配置文件中讀取子類型名稱
String factoryName = readFromConfig();
instance = Class.forName(factoryName).newInstance();
....
}
public Object createSomething();
}
即使如此,我個人的看法是,盡可能避免使用子類的實例。