2012-07-20 90 views
3

在我编码的Java项目中,我最终使用了在构造函数中重写的方法。喜欢的东西:在构造函数中使用重写方法的替代方法,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} 

} 

我现在认识到,虽然在我的情况下,它做工精细,它是有点危险的,因为子类方法被称为已目前仅被构建为一个超类对象(的东西,可能是一个对象在未来添加扩展超类的新类时忽略)。由于创建对象的方式不同,它也不适用于C++。

我能想到让这一轮的唯一方法是向下移动的initialise方法调用的具体类的构造函数:

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()。

我也发现自己在做,在一个构造函数,它是在子类中重写,以决定要实现哪些具体的类使用一个工厂方法更复杂的情境类似的东西。我能想到的另一种方式是保持设计模式,也许可以用两阶段的过程来构建;即最低限度地构建,然后调用第二种方法完成工作。

+2

虽然它不是通常建议调用虚方法从一个构造函数,如果这些方法的目的是初始化,方法大概知道他们不能依靠对象的状态被完全实现(因为这是他们的*存在的d” )这就是说,强制消费者无论如何都需要调用'init()'方法来避免这个问题。 – dlev 2012-07-20 19:07:04

+0

你为什么需要这样做?你能提取复杂的初始化吗?如何建设者,甚至建筑商的层次? – 2012-07-20 23:26:16

回答

0

这实在不是一个好主意,因为你的子类将不能正确的了methodA()和的methodB()被调用时构造。这对于扩展课程的人来说会非常困惑。建议您使用摘要init(),正如dlev在其评论中所建议的那样。

+0

你是否喜欢我在问题中提出的选项?我不确定'抽象'init()是什么意思,或者消费者如何被迫使用它。 – JBradshaw 2012-07-20 19:28:10

+0

或者(A)做你的选择2或者(B)半结构并且在对象被视为完全构造之前需要调用外部可见的init()方法。选择哪个选项取决于你是否设想有许多子类(有利于B)或许多构建这些对象的地方(有利于A)。 – 2012-07-20 19:41:17

0

我不知道你是否让事情比他们需要的更复杂。

在你的榜样,通过了methodA的每一次实施完成的东西,可以移动到不实施类的构造函数。因此,而不是使用SubClass :: methodA,只需将逻辑移入SubClass构造函数。

如果你这样做,你在一些代价获得清晰度可能很难理解在各种初始化位都执行的顺序控制。需要初始化复杂,因为这

+0

感谢您的回复;但是,如果initialise()也做了其他一些对所有扩展超类的类都通用的东西,那该怎么办?唯一的区别是MethodA和methodB()的相应行为? – JBradshaw 2012-07-20 19:36:38

+0

任何常见的初始化都可以在基类的构造函数中,而不是在initialize()中。 – 2012-07-20 19:56:44

1

对象就真的需要通过工厂方法来创建。你确实提到了一个工厂,但是从构造函数中调用,所以听起来并不像直接的方法。如果您只是在基类中拥有一个工厂,公共不可见的构造函数以及决定返回哪个具体类的机制,那么该工厂将轻松实施初始化策略。

0

Bruce Eckel在他的“Thinking in Java”中提出的建议是让类SuperClass的methodA()和方法B()成为final或private(隐式地是final),以便它们可以从超类构造函数访问,派生类将有权访问这些方法,因此不会有危险的重写 - 任何派生类中声明的具有类似签名的方法都将只是新的方法。

相关问题