如何调用子类中的重写方法?重构的潜在候选人

时间:2009-11-02 14:23:30

标签: java refactoring polymorphism override subclass

最初我遇到了一个设计问题,我需要一个超类的五个子类,其中除了两个以外的所有子类都使用相同的通用方法,而另外两个类需要特殊处理。我想避免写五次这个方法;两个特例和三个相同的案例。

所以我让每个类继承SuperClass及其doSomething()方法,并使用自己的doSomeThing方法覆盖SubClassSpecial1和SubClassSpecial2。

这一切都很好,直到我写了一个类似

的方法
void fooBar(SuperClass obj) {
    obj.doSomething()
}

可以将其称为fooBar( new SubClassSpecial1() );

问题是obj变量的运行时类现在是其超类的运行时类,因此它将调用超类中定义的方法。当然,我可以在超类中创建一个抽象的doSometing()方法,并使每个子类实现自己的版本,但这会重复三个类中的代码。我想避免这样做......

如果我通过

进行大量分支,我会失去任何增益多态性
if(obj.getClass().getName() == "SubClassSpecial1" )  ((SubClassSpecial1) obj).doSomething()K;
else if ...

那么我该怎么做才能让设计更优雅,更不讨人喜欢?

3 个答案:

答案 0 :(得分:5)

我对你的这部分问题感到有些困惑:

  

当然,我想要做的是让每个对象调用它自己的doSomething()版本,但没有意识到为了做到这一点,obj需要被声明为子类方法之一。而现在这是一团糟。

当然声明无关紧要,doSomething()方法将始终根据类的运行时类型进行调用。

所以我认为你要做的事情应该很好,例如这些声明都可以用于传递给foobar方法:

SuperClass sc1 = new SubClassSpecial1();
SubClassSpecial2 sc2 = new SubClassSpecial2();
//etc..

答案 1 :(得分:2)

你所描述的应该可以正常工作。

obj.doSomething()实际上是在调用超类的实现吗?如果是,你没有正确地覆盖它。检查您是否在已覆盖的版本中更改了签名。

答案 2 :(得分:1)

当你有这个:

void fooBar(SuperClass obj) {
    obj.doSomething();
}

然后obj编译时类型为SuperClass。这意味着编译器将检查SuperClass是否有doSomething()方法 在运行时,您可以替换SuperClass的子类,这是 Liskov Substitution Principle 。方法foobar()不知道,也不应该知道obj的运行时类型是什么,只是它来自SuperClass,因此可以调用doSomething()

至于你的例子:

fooBar( new SubClassSpecial1() );

在这种情况下,您碰巧知道参数的运行时类型是SubClassSpecial1,它明确地覆盖了doSomething()在所有情况下都会调用正确的方法。

关于重构的一个词。您可能需要考虑重构您的层次结构 您的基类SuperClass应将doSomething()定义为抽象。您需要相同doSomething()实现的三个类应该从具有该特定实现的中间基类继承它。您的两个特殊类应直接从SuperClass继承,并拥有自己的doSomething()实现。