2012-02-03 10 views
5

は、親クラスと関連付けられたクラスに対して、二つの平行な継承ツリーがあります継承とキャスティング:この良いJavaですか?

abstract class EntityA { 
    AssocA myA; 
    abstract void meet(); 
} 

abstract class AssocA { 
    int something; 
    abstract void greet(); 
} 

class AssocAConcrete extends AssocA { 
    void greet() { 
     System.out.println("hello"); 
    } 
    void salute() { 
     System.out.println("I am saluting.") 
    } 
} 

class EntityAConcrete extends EntityA { 
    void meet() { 
     System.out.println("I am about to meet someone"); 
     ((AssocAConcrete)myA).salute(); 
    } 
} 

hereから)このコードを見てみましょう。問題は、23行目である:

((AssocAConcrete)myA).salute();

それは苦痛であると私はすべての私のコードの上にもののようなものを持っています。その行はEntityの具体的な実装の一部ですが、AssocA、AssocAConcreteの具体的な実装を使用したいと思います。

この関係を宣言するための注釈がありますか?あるいは、このデザインを表現するために、より優れた、口語的なJavaの方法がありますか?ありがとう!


私は...

興味深い

いくつかのコードを入れたいので、これは、@Daveに対応しています!だから、呼び出しは次のようになります。

AssocAConcrete myAssoc = new Assoca(); 
EnitityA<T extends AssocA> myEntity = new EntityA<AssocAConcrete>(); 
myEntity.setAssoc(myAssoc); 
myAssoc.salute(); 

はい?かっこいい。私はそれを使用すると思います!

+0

'AssocA myA;'(2行目)の代わりに 'AssocAConcrete myA;'と書くと、それが解決します。しかし、それはコードの残りの部分を破るだろうか? –

+0

ええ、全体的な考え方は、AssocAConcreteのさまざまなバリエーションがあり、EntityAのクライアントがそれに依存したくないということです。 AssocAとEntityAだけを使用するコードでは、どちらか一方または他のConcreteクラスを認識したり、言及したりしないことに注意してください。 2つのコンクリート "A"クラスだけが実装の詳細を知っています。 – pitosalas

答えて

8

私はこれがジェネリックを使用してすっきりたくさんあると思うだろう...

abstract class EntityA<T extends AssocA> { 

    // Basically, this means myA is at least an AssocA but possibly more... 
    T myA; 
    abstract void meet(); 
} 

abstract class AssocA { 
    int something; 
    abstract void greet(); 
} 

class AssocAConcrete extends AssocA { 
    void greet() { 
     System.out.println("hello"); 
    } 
    void salute() { 
     System.out.println("I am saluting."); 
    } 
} 

class EntityAConcrete extends EntityA<AssocAConcrete> { 
    void meet() { 
     System.out.println("I am about to meet someone"); 
     myA.salute(); 
    } 
} 

脇キャストを避けるから、これはまた、それははるかに簡単にあなたのAssocA実装で異なる機能を追加することができます。ダミーの実装(つまり、単に "NotImplementedException"をスローするメソッド)やキャストを使用しないで、やりとりする方法が常にあるはずです。リファクタリングの時間は必ずしも簡単ではありません。言い換えれば、誰もあなたのキャスティングを責めようとしているわけではありません。その後、

以下@pitosalasコメントから...

//Won't work...can't call 'new' on abstract class AssocA 
AssocAConcrete myAssoc = new Assoca(); 

//Instead, do this... 
AssocAConcrete myAssoc = new AssocAConcrete(); 

そして....

// Again, won't work. T is only declaring the type inside your class/method. 
// When using it to declare a variable, you have to say EXACTLY what you're making, 
// or at least something as exact as the methods you're trying to invoke 
EnitityA<T extends AssocA> myEntity = new EntityA<AssocAConcrete>(); 

//Instead do this... 
EnitityA<AssocAConcrete> myEntity = new EntityAConcrete(); 

// Or this... 
EntityAConcrete myEntity = new EntityAConcrete(); 

そして、この必要があります。

EDIT(インスタンス化に関する注記)良いよ...

// Assuming this is defined as `public void setAssoc(T newAssoc) {this.myA = newAssoc;}` 
myEntity.setAssoc(myAssoc); 
myAssoc.salute(); 
+1

私はあなたに+2を与えることができたらいいですか?これはまさにジェネリックのためのものです。なぜ私は何人かの人々が彼らから恥ずかしがっているのか理解できません。ああ、私はジェネリックでよりよく解決された問題を解決するために鋳造を使用することをあなたに責めようとしている人々の一人です。 –

+0

興味深いです。そして、私はこのようにインスタンス化しますか? – pitosalas

+0

どのようにインスタンス化するかは異なります。インスタンス化するために現在使用しているコードはどこですか?あなたの質問を更新して、例を挙げることができますか? – Dave

3

私には疑わしいと思われます。キャストには何もひどいことはありませんが、この場合はsaluteメソッドをAssocAに入れることで問題を解決できます。 AssocAのサブクラスは、その実装を提供することができます。それは継承の利益の一部です。

何が今やっていることは、すべてのEntityAインスタンスがAssocAインスタンスを持っていると言ったが、その後、あなたのmeet方法であなたは基本的にAssocAConcreteインスタンスであることをAssocAインスタンスを強制されます。それが疑わしい部分です。本当にAssocAConcreteが必要な場合は、なぜAssocAが存在しますか?

greetメソッドでは、saluteを呼び出すこともできます(ご意見に基づく)。このように、特定のサブクラスは、スーパークラスで定義された動作greetを指定し、必要な処理を行います。この場合、saluteはプライベートになるか保護される可能性があります。もう1つの実装では、runLikeHellのように簡単に別の処理を行うことができます。

+0

この種のクラスのファミリー間の論理的結合は非常に一般的です。ああ、型システムはそれを表現することをサポートしていません。 – ewernli

+0

@nwgotcodes - 実際は同じものではありません。私は2つの具体的な "A"クラスの実装についての知識を隠したいので、それぞれ互いに知っていますが、AssocAConcreteだけが挨拶する方法を知っています。 AssocXConcreteはそれを行う方法を知らないかもしれません。 – pitosalas

+0

greetメソッドで 'salute'を呼び出します。 – hvgotcodes

0

並列クラス階層の問題は非常にリアルであり、本当にうんざりです。 AssocAConcreteが常にEntityAConcreteとなる論理結合は、型システムでは表現できません。

EntityAConcretemyAのタイプをAssocAConcreteにスーパークラスから隠すことなく特殊化することはできません。私はそれに対処した最も近い仕事は "Family polymorphism"だと思うが、それは主流ではない。

0

あなたが「ミャー」あなたは、参照を使用しているコードの大部分を持っている場合は、そのような別の参照宣言することができます:

public AssocAConcrete myAConcrete = (AssocAConcrete)myA; 

今あなたが新しい参照myAConcreteを使用しての機能にアクセスすることができるがAssocAConcreteクラス。

これを行う必要がある場合は、hvgotcodesのように、AssocAクラスまでメソッドを移動することを検討する必要があります。