这是一个人为的例子:(实际代码中使用的命名方案太混乱了)
我有一个类父亲,它扩展了祖父,它是无法更改的 3rdparty 库的一部分。我还有一些扩展父亲的类;以儿子为例。祖父有一个如下所示的构造函数:
public Grandfather(String name) {...}
这个构造函数中实际发生的事情并不重要。重要的是,无论它在做什么也必须由所有派生类完成,因此调用super(String)
是每个派生类的构造函数的强制性第一行。这里的含义是,Grandfather 的所有后代的构造函数,无论距离多远,都必须始终调用 super(或调用 super 的链式构造函数)作为其第一行。
在我的父亲实现中,我有一个configure(String xml)
解析 xml 文件并使用反射在实例内设置各种参数的方法。其中一些参数在 Grandfather 中,有些在 Father 中,有些甚至可能在 Son 中。每次实例化从父亲派生的类时,都需要运行配置。我最初的想法是configure(String)
像这样简单地添加对我的父亲构造函数的调用:
public Father(String name, String xml) extends Grandfather {
super(name);
configure(xml);
}
这适用于 Granfather 和 Father 实例化,但在 Son 实例化时会崩溃,原因与从构造函数中调用可覆盖方法通常会崩溃的原因基本相同。考虑以下 Son 实现:
public class Son extends Father {
private String occupation = "unknown";
public Son(String name, String xml) {
super(name, xml);
}
}
这是发生的事情:
- 一个新的 Son 使用
new Son(String, String)
. - 在
Son(String, String)
调用内super(String, String)
进行,即。Father(String, String)
. - 内
Father(String, String)
configure(String)
被称为。 configure(String)
找到一个<occupation>
元素并使用反射调用setOccupation("Coal Miner")
.Father(String, String)
退出并执行返回到Son(String, String)
.- 在 Son 退出之前,所有提供默认值的成员都已设置(这在 Java 构造函数的末尾内联)
- 占用被内联覆盖并设置为“未知”。
我想避免重复调用,因为它可能是一个昂贵的操作,所以在每个构造函数的末尾configure(String)
添加一个调用是不可行的。configure(String)
(这将导致configure(String)
Son 实例被调用两次,n 代后代被调用 n 次。
我还想避免configure(String)
在实例化父亲或其任何后代之后手动调用:
Son s = new Son(...);
s.configure(...);
工厂方法在这里可以很好地工作,但由于使用 Grandfather 实例的方式,这是不可能的。长话短说,我几乎从来都不是实例化这些类并且零访问代码的人。
或者换句话说,执行以下操作:
Father f = new Father(...);
将导致configure(...)
被父亲构造函数调用一次,同时:
Son s = new Son(...);
将导致configure(...)
Son 构造函数只调用一次。
鉴于这些限制,任何人都可以想出一种方法来实现我的目标还是我搞砸了?