12

フィードバックの概要

では、この広告を閉じて (これ以上のフィードバックはないと思います)、私が理解したことを要約してみます。

  1. 戦略のパラメーターとして「コンテキスト」を使用すると、回避する必要がある密結合が発生し、おそらくクラスに隠されているはずのプロパティを公開することを余儀なくされる可能性があります。
  2. カップリングを最小限に抑えるには、必要な値を提供するか、少なくとも戦略への具象型の代わりにインターフェイスを使用することをお勧めします。

私は戦略パターンの明確な概要を把握しようとしており、コンテキストに依存する戦略を持つことが良い設計か悪い設計かを自問しています。

次の古典的な実装を見てみましょう

//The strategy
interface IStrategy  
{  
  void Execute();  
}  

class ConcreteStrategyA : IStrategy
{
  public void Execute()
  {
    Console.WriteLine( "Called ConcreteStrategyA.Execute()" );
  }
}

class ConcreteStrategyB : IStrategy
{
  public void Execute()
  {
    Console.WriteLine( "Called ConcreteStrategyB.Execute()" );
  }
}

//The context
class Context
{
  IStrategy strategy;

  // Constructor
  public Context(IStrategy strategy)
  {
    this.strategy = strategy;
  }

  public void UpdateContext(IStrategy strategy)
  {
    this.strategy = strategy;
  }

  public void Execute()
  {
    strategy.Execute();
  }
}

私が見たすべての例には、基本的な引数 (整数など) を取る非常に単純な戦略があります。私が知りたいのは、戦略がコンテキストを使用して作業を行う場合に何か問題があるかどうかです。

それは次のようなものを与えるでしょう

//The strategy
interface IStrategy  
{  
  void Execute(Context arg);  
}  

そして呼び出しは

//The context
class Context
{
  ....

  public void Execute()
  {
    strategy.Execute(this);
  }
}

この「結合」は避けるべきですか?大丈夫ですか?

4

4 に答える 4

7

あなたのアプローチで私が目にする問題の 1 つは、具体的なContextクラスと Strategy クラスのインスタンスの間に密接な結合があることです。これは、Strategy クラスは Context クラスでのみ使用できることを意味します。これを回避する 1 つの方法は、'Context' クラスが実装するインターフェースに戦略クラスを依存させる (または使用する) ことです。

EDIT また、Strategy クラスに Context クラスのインスタンスがある場合、これらのクラスは Context クラスから明示的にデータを取得する必要があります。これは、必要なデータを取得するために、戦略クラスの Context クラスに (必要に応じて) ゲッターを追加することを意味します。ただし、getter を追加するとカプセル化が破られるリスクが生じるため、getter を追加することは必ずしも良い OO プラクティスではありません。

考えられる代替案は、 Context クラスの参照 ( this ) を戦略クラスのメソッドに渡すのではなく、必要なデータのみを戦略クラスに渡すことです

たとえば、Context クラスが次のような場合: (コードは Java です)

Context {
   IStrategy strategy;
   List<Integer> scores;

   public Context(IStrategy strategy)
   {
        this.strategy = strategy;
        scores = new ArrayList<Integer>
   }

   public print() {
       strategy.sort(scores);
   }
}

public interface IStrategy<Integer> {
    public void sort(List<Integer> l);
}

上記のコードでは、Strategy クラスは一般的な Integer リストで動作し、特に Context クラスで使用するようにバインドされていません。さらに、Strategy クラスを定義するときにジェネリック メソッドを使用して、sortメソッドが Integers だけでなくジェネリック型にも適用できるようにすることもできます。

于 2010-01-09T18:09:20.860 に答える
5

私見、大丈夫です。しかし、戦略実装クラスのコンストラクターを介してコンテキストを戦略に渡すことを好みます。

于 2010-01-09T17:57:55.893 に答える
2

あなたのコードはあなたのコードです。あなたにとって意味のあるものを書いてください。ただし、注意事項があります。

戦略パターンの目的は、交換可能な戦略のファミリーを作成することです。多くの設計パターンと同様に、デカップリングからその利点が得られます。この場合、そのような動作を使用するクラスから動作を分離しています。

戦略がコンテキストを引数として取る場合、デカップリングは減少します。コンテキストの変更により、戦略の実装に変更が必要になる場合があります。以前の投稿者が指摘したように、それらを切り離したままにする方法を探すのが最善かもしれません。

そうは言っても、あなたの意図が戦略を交換可能にすることであり、コードがその意図を達成することである限り、問題は見られません。

于 2010-01-09T22:32:37.900 に答える