在我编写的Java项目中,我最终使用了在构造函数中重写的方法。类似的东西:
class SuperClass {
SuperClass() {
intialise();
}
protected void initialise() {
//Do some stuff common to all subclasses
methodA();
methodB();
}
protected abstract void methodA();
protected abstract void methodB();
}
class SubClass1() {
SubClass() {
super();
}
protected void methodA() { //Do something }
protected void methodB() { //Do something }
}
class SubClass2() {
SubClass() {
super();
}
protected void methodA() { //Do something else }
protected void methodB() { //Do something else}
}
我现在意识到,虽然在我的情况下它工作正常但是有点危险,因为SubClass方法在一个目前只被构造为SuperClass对象的对象上调用(当扩展SuperClass的新类时可能会被忽略的东西将来添加)。由于对象的创建方式不同,它在c ++中也不起作用。
我能想到的唯一方法就是将初始化方法调用向下移动到具体的类构造函数:
class SuperClass {
SuperClass() {
}
protected void initialise() {
methodA();
methodB();
}
protected abstract void methodA();
protected abstract void methodB();
}
class SubClass1() {
SubClass() {
super();
initialise();
}
protected void methodA() { //Do something }
protected void methodB() { //Do something }
}...
这是解决这个问题的常用方法吗?所有扩展SuperClass的其他类都需要记住调用initialise(),这似乎是一种耻辱(并且容易忘记)。
我还发现自己在更复杂的情境中做了类似的事情,在构造函数中使用了Factory方法,在子类中重写了它以决定实现哪个具体类。我能想到的唯一另一种方法是将这种设计模式保持原样,或许可以构建一个两阶段的过程;即用最小的构造,然后调用第二种方法来完成工作。
答案 0 :(得分:1)
需要初始化的对象需要通过工厂方法创建。你确实提到了一个工厂,但是从构造函数中调用,所以这听起来也不像是简单的方法。如果您只是在基类中有一个工厂,公开不可见的构造函数,以及决定返回哪个具体类的机制,那么该工厂将很容易实施初始化策略。
答案 1 :(得分:0)
这实际上不是一个好主意,因为当调用其methodA()和methodB()时,您的子类将无法正确构造。对于扩展课程的人来说,这将是非常混乱的。建议您使用抽象init()
代替,正如dlev在他/她的评论中所建议的那样。
答案 2 :(得分:0)
我想知道你是否让事情变得比他们需要的更复杂。
在您的示例中,methodA的每个实现所完成的工作可以移动到执行该实现的类的构造函数中。因此,不要使用SubClass :: methodA,只需将逻辑移动到SubClass构造函数中。
如果你这样做,你可以清楚地看到一些可能难以理解的对各种初始化位执行顺序的控制。
答案 3 :(得分:0)
Bruce Eckel在他的“Thinking in Java”中的建议是让你的methodA()和类SuperClass的方法B()最终或私有(隐式最终),所以它们可以从超类构造函数访问,但没有派生class可以访问这些方法,因此,不会有任何危险的覆盖 - 任何派生类中声明的类似签名的mehtods都只是新方法。