2017-04-03 17 views
2

私はこの問題に遭遇したばかりで、驚いたことがあります。スーパークラスがオーバーライドされたサブクラスメソッドを呼び出すのを防ぐ方法を教えてください。

スーパークラス:

public class Foo { 

    @Override 
    public String toString(){ 
     return String.format("Result = %s", calculate()); 
    } 
    public double calculate(){ 
     return 1; 
    } 
} 

サブクラス:

public class Bar extends Foo { 
    @Override 
    public String toString(){ 
     return String.format("%s", super.toString()); 
    } 
    @Override 
    public double calculate(){ 
     return 123.456; 
    } 
} 

ドライバ:

public static void main(String[] args) { 
    System.out.println(new Bar().toString()); 
} 

私はこのシナリオで希望の出力は、私が手1 出力されています123.456

FooのtoString()がBarのcalculate()を呼び出すのを防ぐにはどうすればよいですか?

+1

'Bar'ではなく' Foo'のインスタンスを作成するか、単に 'Foo#calculate'をオーバーライドしないでください。 –

+0

私が取り組んでいるコードでは、この構造体が仕様通りに必要です –

+1

'bar#calculate'の中で' super.calculate() 'を呼び出せますか? –

答えて

6

あなたはfinalそれをマークし、サブクラスが全くcalculateを上書きさせたくない場合は、次の

public final double calculate() { 
    ... 
} 

あなたがそれらをcalculateを上書きできるようにしたいが、あなたがこの中に上書きを使用したくない場合特定の場所、民間の方法でcalculateの実装を入れて、民間のバージョンを使用します。

public double calculate() { 
    return _calculate(); 
} 
private double _calculate() { 
    return 1.0; 
} 
@Override 
public String toString(){ 
    return String.format("Result = %s", _calculate()); 
} 
+0

私が抱えている問題は、私が書いているものの仕様が上書きする必要があるという仕様です。それ以外の場合は、このような回避策を使用します。 –

+4

仕様を理解していないか、仕様が間違っています。 –

+0

私の教授の実績に基づいて、後者は正しい可能性が高いです。あなたが提案した明白な解決策を延期し、彼女がそれのためにマークを外そうとするなら、これを参考として使用します。 これを確実に確認できる文献はありますか? –

5

をあなたが直接それを行うことはできません - あなたはcalculate()を上書きしていると、あなたは0123を持っているので、オブジェクトの場合、calculate()が使用されたときに呼び出されるのは常にBar.calculate()です。です。もしそれが他の方法であったとしても、合理的なOOOデザインを作ることは非常に混乱し、難しいでしょう!

説明するように、あなたが本当に行動をしたい場合は、通常のソリューションはFoo.toString()コールあなたがFoo.calculate()で持っているロジックを実装非オーバーライド(例えば、privateまたはfinal)ヘルパーメソッドを持っているだけです。 Fooがオーバーライドされた場合でも、toString()は常に同じように動作することが保証されます。次に、Foo.calculate()を実装するには、このヘルパーメソッドを呼び出してDRYの神を喜ばせます。

もちろん、あなたのクラスデザインに何か問題があるかどうかを尋ねるかもしれません。上記の変更は、Foo.calculate()BarオブジェクトでもtoString()でも使用されているが、に直接を呼び出すと、Barという現象が発生するという珍しい状況があることを意味します。したがって、あなたのtoString()の出力は、calculate()を呼び出す人に見られるものと矛盾します。それはめったにあなたが望むものではありません。それが明示的super.calculate()を使用してスーパーcalculate()メソッドを呼び出すために、Barことが可能であることを除いて


。それはスーパークラスで、calculate()への仮想呼び出しがどこにも行かないようにしたいからです。

もちろん、誰かがtoString()を上書きすると、すべての賭けはオフになります。あなたはそれを避けたい場合は常にfinalにすることができます。

+0

ええ、私の先生のスペックの問題は、明示的にこの構造体を使用してtoString()をオーバーライドしているということです。 @ user2357112の答えの下のコメントは、彼女のスペックが実際にここで間違っていることを確認しました。 –

+2

実際の仕様を見ずに言うのは難しいです。 'Bar.toString()'をオーバーライドすると、 'super()。calculate()'を使って 'Foo.calculate()'の項を確実に実装できることに注意してください。 'super.toString()'を呼び出すことによってうまくいくわけではありませんが、いくつかの非常に醜い方法があります。例えば、 'Bar.calculate()'と 'toString()'が呼び出し側であり、その場合は 'super'を使って' Foo.calculate() 'に委譲することができます - 例えば、TLSを使って、 、またはオブジェクトのフィールドを設定します。それはすべてかなりひどいです.... @AnthonyAudette – BeeOnRope

+0

私が使用するソリューションは、醜いにバインドされている、私は仕様が教師の問題であるので、それが立つと論理エラーを残すように誘惑されています。 わかりやすくするために、私は彼女が望む(複雑な)構造について説明します。 Abstract ProjectInvoice> LaborInstance ProjectInvoice> LabourAndMaterialsはLaborを拡張します> LabourAndMaterialsAndEquipmentはLabourAndMaterialsを拡張します。 ProjectInvoiceには抽象メソッドcalculateCost()が含まれています 各サブクラスは計算コストをオーバーライドし、スーパークラスの計算をそれ自身のものに追加します。 それぞれがtoStringをオーバーライドし、その出力に付加情報を付加します。 –

関連する問題