1

ロボットやアイテムなどを使ったボードゲームをプログラミングしています。

ある時点で、ロボットやエネルギーを持つことができるアイテムのエネルギー値を取得する必要があります。これをプログラムする方法は、各ロボットとエネルギーを持つ各アイテムが、フィールドとしてのEnergyContainerクラス(コードの冗長性を防ぐため)とエネルギー値クラスを持つことです。

ここで、基本的に、要素を受け取るメソッドevaluate()を呼び出します。Elementは、ロボットとアイテムが拡張する抽象クラスです。すべての要素にエネルギーコンテナがあるわけではありません。可能であれば、この要素でgetEnergyContainerを呼び出す必要がありますが、それがもちろんそれを持っている要素である場合に限ります。

私はいくつかの解決策を考えることができます:多くのinstanceOfを使用してからキャストします。たとえば、要素がロボットのインスタンスであるかどうかを尋ねる場合は、要素をロボットにキャストし、要素に対してgetEnergyContainerを呼び出します。これには、元素のサブクラスを持つすべてのエネルギーに対してこれを行う必要があるという明らかな欠点があります。

2番目の解決策は、getEnergyContainerメソッドのみを含むインターフェースを定義し、クラスを持つすべてのエネルギーにこれを実装させることです。このインターフェースの唯一の目的は、1つのメソッドを容易にすることであり、ほとんど空になります。

誰かがより良いアイデアを持っていない限り、「最良の」解決策は何ですか?ほぼ空のインターフェースがマーカーインターフェースとして使われていると思いますが、これは唯一の目的なので、少し気が進まないです。

4

3 に答える 3

1

可能であれば、この要素でgetEnergyContainerを呼び出す必要がありますが、それがもちろんそれを持っている要素である場合に限ります。

エネルギーコンテナを持たない要素でそれを呼び出したくないのはなぜですか?エネルギーコンテナがない場合は、の「nullオブジェクト」実装への参照を返すかEnergyContainer、null参照を返します。後で何をしたいかによって異なります。ある種の「中立」エネルギーコンテナを簡単に実装できる場合は、nullオブジェクトパターンが最も簡単なアプローチです。それ以外の場合は、次のようにします。

EnergyContainer container = element.getEnergyContainer();
if (container != null) {
    // Use the container
}

これはある意味で「不純」であると主張する人は間違いありませんが、ほとんどの選択肢よりもほぼ確実に単純です。

于 2012-05-22T15:40:09.077 に答える
1

最善の解決策はgetEnergyContainer()、すべてのエネルギーを含む要素のスーパークラスの1つにメソッドを配置し、各要素クラスでこのメソッドをオーバーライドすることです。このメソッドabstractを作成して、オーバーライドを確実にすることができます。これに対するあなたのスーパークラスは、Elementあなたが言ったからかもしれません:Element is an abstract class which robot and items extend.

于 2012-05-22T15:41:07.467 に答える
0

クラス階層を前提として、インターフェイスを使用した構成を使用して、デフォルトのEnergyContainerの動作を提供します

abstract class Element {

    EnergyContainer ec = new EmptyEnergyContainer();

    int getEnergyValue() {
        getEnergyContainer().getValue();
    }

    EnergyContainer getEnergyContainer() {
        return ec;
    }

    setEnergyContainer(EnergyContainer container) {
        this.ec = container;
    }
}

class Robot extends Element {

    public Robot() {
        this.ec = new ActiveEnergyContainer();
    }
}

class Item extends Element{

    public Item() {
        this.ec = new ActiveEnergyContainer();
    }
}

class Brick extends Element{
    // will have a EmptyEnergyContainer by default
}

EnergyContainerのインターフェース階層は次のようになります

interface EnergyContainer {
    int getValue();
    setValue(int value);
}

class EmptyEnergyContainer implements EnergyContainer {
    @Override
    int getValue() {
        return 0;
    }

    @Override
    setValue(int val) {
        throw Exception("Can not charge an empty container");
    }
}

class ActiveEnergyContainer implements EnergyContainer {
    int value;

    @Override
    int getValue() {
        return 17 + 3;  // calculate the value
    }

    @Override
    setValue(int val) {
        this.value = val // or do some funky calculation
    }
}

実行時に、オブジェクトに新しいEnergyContainerタイプを設定できます。のような複数の親クラスがある場合Elementは、デフォルトの動作を抽象親に追加し、必要に応じてオーバーライドするという同じパターンに従う必要があります。

デフォルトの動作でgetValue()の適切なデフォルト値を返すようにすると、あちこちで使用する必要がなくなりますinstanceof

このコードの潜在的な改善は、

  1. さまざまなEnergyContainerバリアントを作成するためのAbstractFactoryパターン
  2. hasEnergy()値をチェックするのではなく、コードを読みやすくするためのメソッドを含める== 0
  3. Element他の同様の親クラスに同様のメソッドが含まれる場合は、インターフェイスを実装してください
于 2012-05-22T17:00:03.830 に答える