Posted on 2008-10-26 01:42
非鱼 阅读(2543)
评论(1) 编辑 收藏 所属分类:
面向对象设计 、
Java技术
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();
}
即使如此,我个人的看法是,尽可能避免使用子类的实例。
subclass, reference, abstraction, composite, aggregate