2017-07-28 13 views
0

私はこのコードを持っている:サブクラスの型チェックを避けるには?

public abstract class Character { 
    public abstract void attack(Character victim); 
    public abstract void receiveAttack(Attack attack); 
} 

public class CharacterA extends Character { 
    public void attack(Character victim) { 
     if (victim.getClass().equals(this.getClass()) 
      return; 

     victim.receiveAttack(new Attack(BASE_DMG)); 
    } 
} 

アイデアは文字が他の文字から/への攻撃とreceiveAttacksことができるということですが、それはそれ自身のクラスの性格から来て攻撃を受けることができない(CharacterAは別のものを攻撃することはできませんがキャラクターBを攻撃したり、キャラクターBからの攻撃を受けることができます。

私は、オブジェクトのタイプのチェックが悪い匂いであることを知っています。通常、デザインが悪いために発生します。そのため、デザインを変更してオブジェクトタイプを確認する必要はありません?

EDIT

クラスは、実際には名前だけの例を簡素化することで、Character命名されていません。

チームはありません。 CharacterAは、CharacterAではない他のCharacterを攻撃することができます。

FINAL EDIT

みんなありがとう、私はVisitorパターンを使用して、それを解決しました。

+0

私はあなた 'CharacterA'と' CharacterB'が、彼らは共通の祖先の異なる実装する必要があること、とても異なっているが、私はプロパティを使用するかどうかわかりませんそれらを区別するために... –

+0

答えをありがとう。彼らは様々な方法で 'attack'と' receiveAttack'メソッドを実装します。キャラクターBはアーマーを持っているので、被害が少なく、キャラクターAが特殊効果で攻撃を送るかもしれません。プロパティ(Stateパターンのようなもの)を使用しても、そのプロパティのオブジェクトタイプをチェックする必要はありませんか? –

+0

Characterのいくつかのサブクラスがあり、一般的なルールは常にあなた自身のクラスの何かを攻撃することができないということです、あなたが行ったことは完全にうまくいきます。ところで、あなたのクラスの1つに 'java.lang'のクラスと同じ名前を付けると、物事がひどく間違ってしまう可能性があります。 –

答えて

1

非常に単純な解決法/回避策は1つのクラスのみを持つことができ、Characterオブジェクトはすべてという名前のフィールド、つまりcharacterTeamなどを持ちます。 Aチームのキャラクタの場合は、そのフィールドを"A"または"ATeam"に設定します。 Bチームの場合は、そのフィールドを"B"または"BTeam"に設定します。次にattackメソッドのcharacterTeamStringを比較します。

また、私はこのようCharacterという名前のクラスもCharacterという名前charのラッパークラス、と干渉する可能性があるに対して助言します。

+0

これはオブジェクトタイプのチェックと同じではありませんか?つまり、多型や何かOOの方法で解決するのではなく、型を教えてくれるものをチェックするために条件付きを使うことになります。 PS:クラスは実際には 'Character'という名前ではありません。 –

+0

私はあなたのコメントの最後の部分で何を意味するのか少し混乱しています。 Characterという名前のカスタム・クラスと[java.lang.Character](https://docs.oracle.com/javase/7/docs/api/java/lang/Character.html)クラスとの間に矛盾はありませんか? – BlueOxile

0

これは、特定のサブクラスのインスタンスを取得し、このメソッドをノーオペレーションにするか、警告を出力すると宣言されている各サブクラスにオーバーロードされた攻撃メソッドを追加することで実現できます。

CharacterAの署名は、あなたのサブクラスのインスタンスが特定のタイプではなく、基本文字型で宣言されている場合ただし、これはのみ動作します

public void attack(CharacterA victim) 

だろう。

class Character 
{ 
    public void attack(Character victim) 
    { 
     System.out.println(getClass() + " attacking " + victim.getClass()); 
     victim.receiveAttack(new Attack()); 
    } 

    public void receiveAttack(Attack attack) {} 
} 

class CharacterA extends Character 
{ 
    public void attack(CharacterA victim) 
    { 
     System.out.println(getClass() + " cannot attack " + victim.getClass()); 
    } 
} 

class CharacterB extends Character 
{ 
    public void attack(CharacterB victim) 
    { 
     System.out.println(getClass() + " cannot attack " + victim.getClass()); 
    } 
} 

class Attack 
{ 
} 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     CharacterA a = new CharacterA(); 
     CharacterB b = new CharacterB(); 

     a.attack(a); 
     a.attack(b); 
     b.attack(a); 
     b.attack(b); 

     // redeclare a & b to have the base type 
     Character c = a; 
     Character d = b; 

     c.attack(c); 
     c.attack(d); 
     d.attack(c); 
     d.attack(d); 
    } 
} 

出力:

class CharacterA cannot attack class CharacterA 
    class CharacterA attacking class CharacterB 
    class CharacterB attacking class CharacterA 
    class CharacterB cannot attack class CharacterB 
    class CharacterA attacking class CharacterA 
    class CharacterA attacking class CharacterB 
    class CharacterB attacking class CharacterA 
    class CharacterB attacking class CharacterB 
+0

これは基本タイプの場合には良い解決策になります。各キャラクターの重複したコードを除きます。 –

+0

これは、javaの実行時に型の消去があるため、非常に悪い解決策です。 'Character a = new CharacterA();'と 'CharacterA a = new CharacterA();'はプログラムの動作を変更するという事実は、まったく予想外のことです。ただし、ダブルディスパッチは使用できますが、メソッドのオーバーロードはありません(Visitorパターン)。 – plalx

関連する問題