web-dev-qa-db-ja.com

戦略パターンはどのように機能しますか?

それはどのように機能し、何に使用され、いつ使用すべきですか?

63
Jorge Córdoba

戦略パターンを簡単な方法で説明しましょう:

クラスCar()とメソッドrun()があるため、擬似言語で次のように使用します。

_mycar = new Car()
mycar.run()
_

ここで、プログラムの実行中にrun()の動作をオンザフライで変更することができます。たとえば、モーターの故障やビデオゲームの「ブースト」ボタンの使用をシミュレートしたい場合があります。

このシミュレーションを行う方法はいくつかあります。条件付きステートメントとフラグ変数を使用することは1つの方法です。戦略パターンは別のものです:run()メソッドの動作を別のクラスに委任します。

_Class Car()
{
    this.motor = new Motor(this) 

    // passing "this" is important for the motor so it knows what it is running

    method run()
    {
        this.motor.run()
    }

    method changeMotor(motor)
    {
        this.motor = motor 
    }

}
_

車の動作を変更したい場合は、モーターを変更するだけです。 (実際のプログラムよりプログラムの方が簡単ですよね?;-))

複雑な状態が多数ある場合に非常に便利です。状態をより簡単に変更および維持できます。

78
e-satis

問題

戦略パターンは、さまざまなstrategiesによって実装または解決される可能性がある(または予測される可能性がある)問題を解決するために使用され、そのような場合に明確に定義されたインターフェースを所有します。各戦略はそれ自体完全に有効であり、実行時にアプリケーションがそれらを切り替えることができる特定の状況では、いくつかの戦略が望ましいです。

コード例

namespace StrategyPatterns
{
  // Interface definition for a Sort algorithm
  public interface ISort
  {
    void Sort(List<string> list)
  }

  // QuickSort implementation
  public class CQuickSorter : ISort
  {
    void Sort(List<string> list)
    {
      // Here will be the actual implementation
    }
  }

  // BubbleSort implementation
  public class CBubbleSort : ISort
  {
    void Sort(List<string> list)
    {
      // The actual implementation of the sort
    }
  }

  // MergeSort implementation
  public class CMergeSort : ISort
  {
    void Sort(List<string> list)
    {
      // Again the real implementation comes here
    }
  }

  public class Context
  {
    private ISort sorter;

    public Context(ISort sorter)
    {
      // We pass to the context the strategy to use
      this.sorter = sorter;
    }

    public ISort Sorter
    {
      get{return sorter;)
    }
  }

  public class MainClass
  {
    static void Main()
    {
       List<string> myList = new List<string>();

       myList.Add("Hello world");
       myList.Add("Another item");
       myList.Add("Item item");

       Context cn = new Context(new CQuickSorter());
       // Sort using the QuickSort strategy
       cn.Sorter.Sort(myList);
       myList.Add("This one goes for the mergesort");
       cn = new Context(new CMergeSort());
       // Sort using the merge sort strategy
       cn.Sorter.Sort(myList);
    }
  }
}
38
Jorge Córdoba
  • 戦略とは?戦略は、特定の目標を達成するために設計された行動計画です。
  • 「アルゴリズムのファミリーを定義し、それぞれをカプセル化して、それらを交換可能にします。戦略により、アルゴリズムはそれを使用するクライアントから独立して変化することができます。」 (ギャングフォー);
  • それぞれが潜在的な動作を表す一連のクラスを指定します。これらのクラスを切り替えると、アプリケーションの動作が変わります。 (戦略);
  • この動作は、実行時(ポリモーフィズムを使用)または設計時に選択できます。
  • 抽象化をインターフェースに取り込み、実装の詳細を派生クラスに埋め込みます。

enter image description here

  • 戦略の代替手段は、条件付きロジックを使用してアプリケーションの動作を変更することです。 (悪い);
  • このパターンを使用すると、アプリケーションのすべてまたは一部を再コーディングして再テストする必要がなく、特定の動作を追加または削除することが簡単になります。

  • 良い使い方:

    • 同様のアルゴリズムのセットがあり、アプリケーションの異なる部分でそれらを切り替える必要がある場合。戦略パターンを使用すると、ifを回避し、メンテナンスを容易にすることができます。
    • スーパークラスに、必ずしもすべてのサブクラスに意味をなさない新しいメソッドを追加する場合。インターフェースを従来の方法で使用する代わりに、新しいメソッドを追加して、新しい機能性インターフェースのサブクラスであるインスタンス変数を使用します。これはコンポジションと呼ばれます。継承によってアビリティを継承する代わりに、クラスは適切なアビリティを持つオブジェクトで構成されます。
21
Malf

Strategy Pattern Wikipediaの記事から直接

戦略パターンは、アプリケーションで使用されるアルゴリズムを動的に交換する必要がある状況で役立ちます。戦略パターンは、アルゴリズムのファミリーを定義し、それぞれをオブジェクトとしてカプセル化し、それらを交換可能にする手段を提供することを目的としています。戦略パターンにより、アルゴリズムを使用するクライアントとは独立してアルゴリズムを変更できます。

6
Bill the Lizard

密接に関連するパターンはデリゲートパターンです。どちらの場合も、一部の作業は他のコンポーネントに渡されます。私が正しく理解している場合、これらのパターンの違いはこれです(間違っている場合は修正してください)。

  • Delegateパターンでは、デリゲートは囲んでいる(デリゲートする)クラスによってインスタンス化されます。これにより、継承ではなく構成によるコードの再利用が可能になります。囲んでいるクラスは、デリゲートの具象タイプを認識している場合があります。 (ファクトリを使用するのではなく)コンストラクタ自体を呼び出す場合。

  • Strategyパターンでは、戦略を実行するコンポーネントは、そのコンストラクターまたはセッター(信仰に従って)を介して、囲んでいる(using)コンポーネントに提供される依存関係です。 usingコンポーネントは、どの戦略が使用されているかをまったく認識していません。戦略は常にインターフェースを介して呼び出されます。

誰か他の違いを知っていますか?

6
Andrew Swan

すでに素晴らしい答えに追加するには:戦略パターンは、1つまたは複数の関数を別の関数に渡すことと非常に類似しています。戦略では、これは、関数をオブジェクトでラップした後、オブジェクトを渡すことによって行われます。一部の言語は関数を直接渡すことができるため、パターンをまったく必要としません。しかし、他の言語は関数を渡すことができませんが、 できる オブジェクトを渡す;次にパターンが適用されます。

特にJavaのような言語では、言語のZoo型はかなり小さく、オブジェクトを作成することによって拡張する唯一の方法であることがわかります。したがって、問題のほとんどの解決策はパターンを考え出すことです。特定の目標を達成するためにオブジェクトを構成する方法。型の動物園が豊富な言語では、問題を簡単に解決できる方法が多くありますが、型の種類が多いと、型システムの学習により多くの時間を費やす必要があります。動的タイピングの規律を持つ言語は、問題を巧妙に回避することもよくあります。

5