0

タイプ「Element」の多くの異なる要素を含むArrayListがあると仮定しましょう。それらはすべて、無限ループで画面に描画されます。

これらの「要素」は、「移動可能」、「選択可能」などの0..nインターフェースを実装できます。

これまでに試したのは、すべての要素を反復処理して、次のようなインターフェイスを確認することです。

ArrayList<Element> allElements;
...

for (Element element : allElements) {
  if (element instanceof Movable) {
    ((Movable)element).move();
  }
  if (element instanceof Selectable) {
    ...
  }

  element.draw();
}

しかし、私はそのアプローチに満足していません。なぜなら、それはオープン/クローズドの原則(そしておそらく他の何千もの原則も)に違反しているからです。もちろん、実装するインターフェイスに従って各要素が応答するように再設計することもできます。

for (Element element : allElements) {
  element.move(); // element checks itself if it can move, and if true moves
  ...
}

欠点は、Elementクラスが可能な動作ごとにシグネチャを提供する必要があることです。つまり、すべてのインターフェイスのメソッドを提供し、子クラスでそれらをオーバーライドする必要があります。Elementクラスを肥大化させるので、それも私が望んでいることではありません。

また、次のようなインターフェイスで要素を選択してみました。

getElementsByInterface(Movable, allElements) { ... }

(移動可能はインターフェースであり、allElementsはArrayListです)

しかし、それはコンパイルされません。Javaは実行時にインターフェースを認識しなくなったようです。

簡単に言えば(私のおそらく過度に冗長な投稿で申し訳ありません):配列要素をその能力(/インターフェース)に従って反応させるための最良の設計ソリューションは何ですか?

4

4 に答える 4

2

このアプローチには本質的に何も問題はありません。

このシナリオには、基本的に2つのアプローチがあります。

  1. ポリモーフィズムとVisitorパターンを使用します。LSP(のインターフェースの側面)により、これにより、すべてのアクションを実装する必要がある各ハンドラーについて説明されている「欠点」が発生します。

  2. ローカル型ベースのスイッチングを使用する(これは、このアプローチが受け入れられる/一般的なADTを備えたScalaのような言語でより一般的な場所です。Java構文は比較すると少し扱いに​​くいです)。

インターフェイスが使用されており、実装に「アクション」が残っているため、ここでは(ポリモーフィック)オープン/クローズの違反はありません(ポリモーフィズムをサポートしているため、「オープン」)。そうでないのは行動の選択だけです。

于 2012-09-25T04:31:13.453 に答える
2

正しい答えは、コードベース全体でそのまたは同様のswitchステートメントが何回出現するかによって決まることをお勧めします。

正確に1か所で発生する場合は、そのままにしておくとよいでしょう。

多数の場所で発生する場合は、ビジターパターン(または、予想される変更の性質によっては、コマンドパターンとコンポジットパターンを一緒に使用して)を使用してリファクタリングすることをお勧めします。

于 2012-09-25T04:54:47.847 に答える
1

ここでは、 Visitorパターンが役立つ場合があります。

于 2012-09-25T04:01:55.593 に答える
0

なぜこれにリフレクションを使用できないのですか?

私はあなたに一方通行を提案することができます。

CanDoActionという新しいインターフェースを作成します。

public interface CanDoAction{
    String getAction();
}

次に、これからインターフェイスを拡張し、getActionメソッドの場合、対応するインターフェイスに対して呼び出される関数の名前を返します。たとえば、Movableを実装するクラスの場合、getActionに対して「move」を返します。

次に、ループ中:

for (Element element : allElements) {
    String actionName = ((CanDoAction)element).getAction();

    try {
        element.getClass().getDeclaredMethod(actionName, null)
                .invoke(element, null);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
于 2012-09-25T04:20:02.190 に答える