1

特定の種類の情報を2つの異なる方法で表示する必要があるSwingGUIがあるとします。デザインパターンの観点からは、おそらくここで戦略パターンを使用します。ディスプレイコンポーネントとクライアント間の通信が次のように機能する方法を定義するインターフェイスを作成します。

public interface Foo {
  void showData(Data bar)
}

次に、実際のアクションは、Fooを実装するさまざまなコンポーネントによって実行され、実際の作業を実行するために作成およびプラグインできます。

さて、実際のコンポーネントがjava.awt.Componentsの場合、どうなりますか?私が見ているように、Componentはクラスであるため、型キャストが混乱します。次のような実装を想定しましょう。

public class Baz extends Component implements Foo {
  ...
}

クラスBazのオブジェクトを渡したい場合、メソッドはパラメータタイプとして「Component」または「Foo」のいずれかを使用できます。問題は、一部のメソッドがComponentとFooの両方であるオブジェクトを必要とすることです(たとえば、オブジェクトをJPanelに追加してから、インターフェイスメソッドを呼び出すデータを提供するためshowData())。

私が見ているように、これを実現するためのいくつかの選択肢があります。

  • 参照をコンポーネントとして渡し、Fooにキャストできます。前に、参照がFooのインスタンスであることを確認する必要があり、この要件が満たされない状況を処理する必要があります。もう1つの問題は、コンポーネントが渡したメソッドのクライアントと通信する必要があることです。これは、扱いにくくエラーが発生しやすいFooも実装する必要があります。
  • Fooでも同じことができます
  • メソッド「ComponentgetComponent()」をFooインターフェースに追加すると、実装は常に「this」を返します。この定型メソッドは、Componentの抽象的なサブクラスに入れることができます。このソリューションは、私が必要としないインターフェースメソッドと私が必要としない追加のサブクラスを意味します。
  • 同じオブジェクトへの2つの参照、1つのコンポーネントと1つのFoo参照を渡すことができます。ただし、内部的には、両方の参照が同じオブジェクトに属していることを確認する必要があります。そして、私はこの要件が満たされない状況に対処しなければなりません。
  • Componentの抽象サブクラスを使用し、抽象メソッドを使用してインターフェイスを定義できます。これにより、タイプセーフな方法で参照を渡すことができますが、インターフェイスと実装を分離し、インターフェイス分離の原則を維持するという、優れたOOPプラクティスを破ることができます。

したがって、これらのソリューションはすべて単なる回避策です。私が見逃している解決策はありますか?私は何をすべきか?

4

1 に答える 1

0

あなたが言及したように、私は戦略デザインパターンを使用しますが、おそらく別のコンテキストで使用します. Foo両方と1 つのクラスを "靴べら" にしようとする際の問題Componentは、コードの複製を必要とする実装の組み合わせができることです。

たとえば、 の次の実装があるとしますComponent: (Swing を使用してから時間が経ちすぎているため、これらのクラスは存在しない可能性があります)

  • JPanel
  • JButton
  • Jメニュー

また、次の実装もありましたFoo

  • MyFoo
  • ヒスフー
  • 私たちのフー
  • ホワット・ザ・フー

そして、それらのすべての組み合わせを想像してみてください。それは、クラスの爆発と呼ばれるものです。これは、戦略パターンの古典的な正当化です。

HAS-A次のようにリレーションシップを使用する代わりに、必要なクラスごとにリレーションシップを使用する一種のコンテナ クラスを作成しIS-Aます:

class ComponentFooHandler {
  Component component_;
  Foo fooImpl_;

  inline Foo getFoo()  {return fooImpl_;}
  void setFoo(Foo f)   {fooImpl_ = f;}

  Component getComponent()        {return component_;}
  void setComponent(Component c)  {component_ = c;}

  void doAction() {
    component_.someAction();
    fooImpl_.anotherAction();
  }
}

その後、個別にさまざまな実装を作成する必要がありますFoo。その後、必要に応じてComponentとのFoo実装を組み合わせることができ、Foo impl コードを複製する必要はありません。また、テンプレート パターンと同様に、詳細を知らなくてdoAction()も両方Fooで操作できるメソッドを呼び出すことができることにも注意してください。Component

元の質問の問題を解決するには:

  • が必要な場合は、ハンドラ インスタンスComponentを呼び出しますgetComponent()
  • が必要な場合は、ハンドラ インスタンスFooを呼び出しますgetFoo()
  • 両方を 1 つに必要とするメソッドを作成することは避け、メソッド引数を 2 つに分割します。
  • または、単に周りを回ることを検討してくださいComponentFooHandler
于 2012-04-23T10:00:46.327 に答える