コンピュータプログラミングにおいて、ストラテジーパターン(ポリシーパターンとも呼ばれる)は、実行時にアルゴリズムを選択できるようにする振る舞いソフトウェア設計パターンです。単一のアルゴリズムを直接実装する代わりに、コードはアルゴリズム群の中からどれを使用するかについて実行時指示を受け取ります。[ 1 ]
ストラテジーは、アルゴリズムがそれを使用するクライアントとは独立して変化するようにします。[ 2 ]ストラテジーは、ガンマらによる影響力のある書籍『デザインパターン』[ 3 ]に含まれるパターンの1つで、柔軟で再利用可能なオブジェクト指向ソフトウェアの設計方法を記述するためにデザインパターンを使用するという概念を普及させました。どのアルゴリズムを使用するかの決定を実行時まで延期することで、呼び出し元のコードをより柔軟で再利用可能にすることができます。
例えば、入力データの検証を行うクラスは、ストラテジーパターンを使用して、データの種類、データのソース、ユーザーの選択、その他の識別要因に応じて検証アルゴリズムを選択することができます。これらの要因は実行時まで不明であり、根本的に異なる検証が必要になる場合があります。検証アルゴリズム(ストラテジー)は、検証オブジェクトとは別にカプセル化されているため、コードの重複なしに、システムの異なる領域(あるいは異なるシステム)にある他の検証オブジェクトで使用できます。
一般的に、ストラテジーパターンはコードへの参照をデータ構造に格納し、それを取得します。これは、ネイティブ関数ポインタ、第一級関数、オブジェクト指向プログラミング言語のクラスまたはクラスインスタンス、あるいはリフレクションを介して言語実装の内部コード格納場所にアクセスするなどのメカニズムによって実現できます。

上記のUMLクラス図では、Contextクラスはアルゴリズムを直接実装していません。代わりに、アルゴリズムを実行するためのインターフェース ( )Contextを参照しており、アルゴリズムの実装方法に依存しません。クラスとクラスはインターフェースを実装しており、つまり、アルゴリズムを実装 (カプセル化) しています。UML シーケンス図は 、 実行時の相互作用を示しています。オブジェクトは、アルゴリズムをさまざまなオブジェクトに委譲します。まず、オブジェクトを呼び出し、アルゴリズムを実行して結果を に返します。その後、戦略を変更し、オブジェクトを呼び出し、アルゴリズムを実行して結果を に返します。Strategystrategy.algorithm()ContextStrategy1Strategy2StrategyContextStrategyContextalgorithm()Strategy1ContextContextalgorithm()Strategy2Context



ストラテジーパターンによれば、クラスの振る舞いは継承されるべきではなく、インターフェースを用いてカプセル化されるべきである。これは、クラスは拡張に対しては開放的であるべきだが、変更に対しては閉鎖的であるべきだとするオープン・クローズド原則(OCP)と整合している。
例えば、車のクラスを考えてみましょう。車にはブレーキと加速という2つの機能があります。加速とブレーキの動作はモデルによって頻繁に変わるため、これらの動作をサブクラスで実装するのが一般的なアプローチです。しかし、このアプローチには大きな欠点があります。加速とブレーキの動作は、新しい車のモデルごとに宣言する必要があるのです。モデルの数が増えるにつれて、これらの動作を管理する作業は大幅に増加し、モデル間でコードを重複させる必要が生じます。さらに、各モデルのコードを調べなければ、それぞれの動作の正確な性質を把握するのは容易ではありません。
ストラテジーパターンは、継承ではなくコンポジションを使用します。ストラテジーパターンでは、動作は個別のインターフェースと、これらのインターフェースを実装する特定のクラスとして定義されます。これにより、動作と、その動作を使用するクラスとの間の結合度をより適切に低減できます。動作は、それを使用するクラスを壊すことなく変更でき、クラスは、使用する特定の実装を変更するだけで、大きなコード変更を必要とせずに動作を切り替えることができます。動作は、設計時だけでなく実行時にも変更できます。たとえば、車のオブジェクトのブレーキ動作は、メンバーを次のように変更することで、BrakeWithABS()からに変更できます。Brake()brakeBehavior
Brake * brakeBehavior = new Brake ();パッケージorg.wikipedia.examples ;/* カプセル化されたアルゴリズム群* インターフェースとその実装*/ interface IBrakeBehavior { public void brake (); }class BrakeWithABS implements IBrakeBehavior { public void brake () { System . out . println ( "ABS適用時のブレーキ" ); } }class Brake implements IBrakeBehavior { public void brake () { System . out . println ( "Simple Brake applied" ); } }// 上記のアルゴリズムを相互に使用できるクライアントabstract class Car { private IBrakeBehavior brakeBehavior ;public Car ( IBrakeBehavior brakeBehavior ) { this . brakeBehavior = brakeBehavior ; }public void applyBrake () { brakeBehavior.brake ( ) ; }public void setBrakeBehavior ( IBrakeBehavior BrakeType ) { this .ブレーキ動作=ブレーキタイプ; } }// クライアント 1 はコンストラクタで 1 つのアルゴリズム (Brake) を使用します。class Sedan extends Car { public Sedan () { super ( new Brake ()); } }// クライアント 2 はコンストラクタで別のアルゴリズム (BrakeWithABS) を使用します。class SUV extends Car { public SUV () { super ( new BrakeWithABS ()); } }// Car の例を使用するpublic class CarExample { public static void main ( String [] arguments ) { Car sedanCar = new Sedan (); sedanCar . applyBrake (); // これによりクラス "Brake" が呼び出されますCar suvCar = new SUV (); suvCar.applyBrake (); // これによりクラス「BrakeWithABS」が呼び出されます//ブレーキ動作を動的に設定するsuvCar.setBrakeBehavior ( new Brake ( )); suvCar.applyBrake (); // これによりクラス「Brake 」が呼び出されます} }{{cite book}}: CS1 maint: 複数の名前: 著者リスト (リンク)