[Behavioral Patterns] - Strategy


意図する


ポリシーは、一連の動作をオブジェクトに変換し、元のコンテキストオブジェクト内で互いに互換性を持つ動作設計モードです.
元のオブジェクト(コンテキストと呼ばれる)は、ポリシーオブジェクトへの参照を保持し、実行アクションを委任します.コンテキストの動作を変更するには、他のオブジェクトは、現在接続されているポリシーオブジェクトを他のオブジェクトに置き換えることができます.

質問する


ナビゲーションアプリケーションをしているとします.アプリケーションで最も要求される機能は、自動的にパスプランを生成し、ユーザーがアドレスを入力すると地図に表示される宛先の最速パスが表示されます.
アプリの初期には、道路上の経路を表示することで、自動車旅行の人は大好きですが、誰もが自動車旅行を利用しないので、歩行経路計画、公共交通経路計画など多くの選択肢が追加されました.
これはただの始まりで、後で自転車に乗る人に機能などの選択肢を追加すれば、コードはますます膨張します.

ナビゲーションのコードが膨張した.
ビジネスの観点から見ると、このアプリケーションは成功したが、技術面ではトラブルをもたらした.新しいルーティングアルゴリズムを追加するたびに、ナビゲータの基本クラスのサイズが2倍になります.
単純なエラー修正でも、距離スコアを少し調整しても、アルゴリズムの1つを変更するとクラス全体に影響し、実行中のコードにエラーが発生する可能性が高くなります.
そしてチームワークも非効率になりました.発表に成功した後、チームメンバーはMergeConflictの解決に時間がかかりすぎたと愚痴をこぼし、新しい機能を実現するには、他のユーザーが生成したコードと競合し、同じ巨大な顧客群を変更する必要があります.

解決策


ポリシー・モードでは、特定のタスクを異なる方法で実行するクラスを選択し、これらのアルゴリズムをすべてポリシーと呼ばれる独立したクラスに抽出することを推奨します.(Stateモードと似ていますが、Stateは以下の状態についてある程度理解していますが、このモードではありません)
コンテキストという名前の元のクラスでは、フィールドはいずれかのポリシーへの参照を格納するために使用され、コンテキストは自動的に実行するのではなく、関連するポリシーオブジェクトに委任されます.
クライアントは、コンテキストで適切なアルゴリズムを選択することなく、必要なポリシーをコンテキストに渡すことができます.したがって,コンテキストはポリシーを理解せず,同じ汎用インタフェースを介してすべてのポリシーと共に動作し,選択したポリシー内でパッケージアルゴリズムをトリガする単一の方法にのみ曝露する.
これにより、コンテキストは特定のポリシーとは独立しており、コンテキストのコードや他のポリシーを変更することなく、新しいアルゴリズムを追加したり、既存のアルゴリズムを変更したりすることができます.

パス計画ポリシー
ナビゲーション・アプリケーションでは、各ルーティング・アルゴリズムは、単一のbuildRouteメソッドを使用して独自のクラスに抽出できます.メソッドは出発地とターゲットを受け入れ,経路のチェックポイント集合に戻る.
同じ引数が与えられても、ルーティングクラスごとに異なるパスを作成できますが、メイン・ナビゲータの基本的なタスクはレンダリングなので、どのアルゴリズムを選択したのかはあまり気にしません.クラスにはアクティブなルーティングポリシーを切り替える方法があるため、ユーザーインタフェースのボタンなどのクラスのクライアントは、現在選択されているルーティング動作を他の動作に変更することができます.

現実的類似性



空港戦略
空港に行くときは、バス、タクシー、自転車などの交通手段を選ぶことができます.

こうぞう



  • コンテキストは、ポリシーインタフェースのみを介してオブジェクトと通信する特定のポリシーへの参照を保持します.

  • 戦略インタフェースはすべての具体的な戦略の共通点である.コンテキストを宣言してポリシーを実行する方法.

  • 具体的なポリシーは、コンテキストで使用されるアルゴリズムの多様な変異体を体現している.

  • アルゴリズムを実行するたびに、コンテキストは関連するポリシーオブジェクトの実行方法を呼び出します.コンテキストは、どのタイプのポリシーを使用するか分からないし、アルゴリズムがどのように実行されているか分からない.

  • クライアントは、特定のポリシー・オブジェクトを作成し、コンテキストに渡します.コンテキストはセッションを提供し、クライアントは実行時にコンテキストに関連するポリシーを置き換えることができます.
  • 適用性


  • オブジェクト内で異なるタイプのアルゴリズムを使用し、実行時に1つのアルゴリズムから別のアルゴリズムに切り替えることができる場合は、ポリシーモードを使用します.

  • いくつかの操作の実行方法が異なり、類似のクラスがたくさんある場合は、ポリシーを使用します.

  • このモードを使用して、クラスのビジネスロジックと、論理コンテキストで重要でない可能性のあるアルゴリズムの実装詳細を分離します.

  • クラスに同じアルゴリズムの異なるバリエーション間で切り替える大規模な条件演算子がある場合は、モードが使用されます.
  • メリットとデメリット


    長所

  • の実行時にオブジェクト内部で使用されるアルゴリズムを交換することができる.
  • アルゴリズムを使用するコードからアルゴリズムの実装詳細を分離することができる.
  • の代わりに構成で継承できます.
  • OCP
  • 短所

  • アルゴリズムがいくつかしかなく、ほとんど変化していない場合、プログラムをモードに基づいて提供される新しいクラスおよびインタフェースに過度に複雑化する理由はない.
  • クライアントは、適切な戦略を選択するために、戦略の違いを理解する必要があります.
  • 現在のプログラミング言語の多くは、匿名関数セットで異なるバージョンのアルゴリズムを実現できる関数型サポートを備えています.次に、これらの関数をポリシーオブジェクトのように正確に使用できますが、コードを展開するために追加のクラスとインタフェースを使用する必要はありません.
  • Strategy in TypeScript


    TypeScriptのパターンを使う


    複雑度:★☆☆
    人気:★★★
    使用例:ポリシー・モードはTSコードで非常に一般的です.異なるフレームワークでよく使用され、クラスを拡張せずにクラスの動作を変更できる方法を提供します.
    識別:ポリシー・モードは、ネストされたオブジェクトが実際の操作を実行し、そのオブジェクトを他のオブジェクトに置き換えることができる方法と考えられます.index.ts
    // 컨텍스트는 클라이언트의 관심 인터페이스를 정의한다.
    class Context {
      private strategy: Strategy;
    
      constructor(strategy: Strategy) {
        this.strategy = strategy;
      }
    
      public setStrategy(strategy: Strategy) {
        this.strategy = strategy;
      }
    
      public doSomeBusinessLogic(): void {
        console.log("Context: Sorting data using the strategy (not sure how it'll do it)");
        const result = this.strategy.doAlgorithm(['a', 'b', 'c', 'd', 'e']);
        console.log(result.join(','));
      }
    }
    
    interface Strategy {
      doAlgorithm(data: string[]): string[];
    }
    
    class ConcreteStrategyA implements Strategy {
      public doAlgorithm(data: string[]): string[] {
        return data.sort();
      }
    }
    
    class ConcreteStrategyB implements Strategy {
      public doAlgorithm(data: string[]): string[] {
        return data.reverse();
      }
    }
    
    const context = new Context(new ConcreteStrategyA());
    console.log('Client: Strategy is set to normal sorting.');
    context.doSomeBusinessLogic();
    
    console.log('');
    
    console.log('Client: Strategy is set to reverse sorting.');
    context.setStrategy(new ConcreteStrategyB());
    context.doSomeBusinessLogic();
    결과

    サマリ


    ポリシー・モードを使用すると、コンテキスト内の一連の動作をオブジェクトに変換し、元のコンテキスト・オブジェクト内で互いに互換性を保つことができます.これにより、ポリシー・オブジェクトへの参照が保持され、実行アクションが委任されます.
    これにより、クライアントは使用時にポリシーに基づいて行動し、ビジネスロジックとアルゴリズムの詳細を分離できます.
    反応器では,propsとして関数を簡単に受け入れ,素子上で動作することも戦略モードとなる.

    コメントサイト

  • https://refactoring.guru/design-patterns/strategy
  • https://refactoring.guru/design-patterns/strategy/typescript/example