java - クラス階層とセットアップ

原文 java oop

だから私は私の研究のいくつかを統合するために単純なRPGのようなテキストベースのゲームを作ろうとしています、そして私はこのタイプのセットアップを実装する最良の方法がどのようであるかと思っています:

Fighterというインターフェース> AbstractFighterによって実装> MagicFighterおよびStrengthFighterは、AbstractFighterを拡張します。 (元々、MagicFighterとStrengthFighterには独自のインターフェイスがあり、独自の動作が追加されていました)が...

混乱するのは、これらの2種類のファイターからプレイヤーが選択できるようにすることです。これをリスト(ファイター)に保存します。したがって、明らかに、返されるタイプは常にFighterであり(ユーザーが選択するFighterの実装がわからないため)、Fighterインターフェースにあるメソッドのみを呼び出すことができます。

私ができることの1つは、さまざまなFighter実装に固有のメソッドを呼び出す必要があるたびに、プレイヤーが選択したもののチェックを記述してダウンキャストすることです。しかし、これは多くの繰り返しコードを意味し、面倒な= /に聞こえます。

別の可能性は、チェックを実行し、選択に基づいてユーザーをList(StengthFighter)またはList(MagicFighter)に追加することですが、最終的にはこれは前の「解決策」とまったく同じ問題を抱えています。

最後に考えられるのは、Fighterの各実装をミラー化して、それぞれの動作のバージョンが常に存在するようにすることです。だから例えば
void regen(); Fighterインターフェースで、StrengthFighterとMagicFighterに異なる方法で実装されています(Magic fighterはマナを再生成する可能性があり、strength fighterはattack()を使用するたびに怒りを再生成する可能性があります(これは、ManaFighterがregen()を実装する必要があるため、明らかにパブリックです、ただし、StrengthFighter内での使用はプライベートです)。

とにかく、おそらくあなたは今では要点を理解しているので、テキストウォールをこれ以上保存しないでください。

結局のところ、これは私の実装の欠陥ですか?それとも、これはオブジェクト指向プログラミングの必然性なのでしょうか?つまり、結局のところ、型を決定する決定をユーザーに求める場合、Javaは結果がどの型である必要があるか(したがって、そのメソッドを使用するか)をどのようにして知ることができるのでしょうか。
答え
これは、質問の解釈に基づく大まかなクラスの実装です。インターフェース、そして実装、そして個々のタイプの元の定義は複雑に感じられます。代わりに、それらの表現ではなく、個々のFighterを操作したいと考えています。

class Fighter {
    int hp;

    void attack() {

    }

    void move() {

    }

    void regen() {
        hp++;
    }
}

class MagicFighter extends Fighter {
    int mana;

    @Override
    void regen() {
        mana++;
        //we don't regen hp because we're magic-type.
    }
}

class StrengthFighter extends Fighter {
    int rage;

    @Override
    void attack() {
        super.attack();
        specialRegen();
    }

    void specialRegen() {
        rage++;
    }

    @Override
    void regen() {
        // does nothing
    }

    void berserk() {
        rage--;
    }
}


この場合、Fighterのリストを保存できます。

List<Fighter> fighters = new List<>();


新しい戦闘機を作成するときは、ユーザーが何を望んでいるかを判断し、それを戦闘機のリストに追加します。

    if (selection.equals("StrengthFighter")) {
        Fighter fighter = new StrengthFighter();
        fighters.add(fighter);
    }


次に、すべてのメソッドを通常どおり呼び出します。 Fighter.moveなど、2つのクラス間で共有されているものは上書きされません。 StrengthFighter.regenのように、1つのタイプでのみ機能しないものは上書きされます。特定のタイプに特別な追加機能があるものはすべて、追加機能を実装し、superのようにStrengthFighter.attackを呼び出します。

基本的に、あなたはすでに正しい考えを持っていますが、基本的には、Fighterが可能な限り多くの共有作業を実行し、舞台裏のタイプに基づいて個々のアクションを実装したいと考えています。タイプをチェックする必要がある場合は、StrengthFighter.berserkなど、そのタイプのFighterに固有の何かである必要があります。

これにより、本当に重要な場合を除いて、タイプをチェックする必要が減ります。
関連記事

java - Usage TrackerのJavaプロパティファイルでユーザー名を解決する

java - ボタン付きのビューページャーでフラグメント間をスワイプできません

java - 同じアクティビティ内のAdMobとWebViewが機能しない(Androidアプリ)

java - Android Gstreamer SDKでANativeWindow_lockがエラー-22を返す

java - Lucene Library 4.1.0でプラス記号をエスケープする方法

java - 特定のメソッドからのメソッドへの呼び出しの検出または防止

java - Randomインスタンスをグローバルに宣言する必要があります。もっと良い方法はありますか?

java - ArrayList全体にクラスメソッドを適用する

java - Java 2次元配列と平均

java - JAVAのDOM to XMLが機能しない