GoF本 Strategy
ねらい
AKA
- Policy
つかいどころ
- ふるまいだけが異なる似通ったクラスが複数ある
- いくつかのアルゴリズムを選べるようにしたい
- 時間・空間・美しさ等のトレードオフ
- アルゴリズム固有のデータを隠蔽したい
- 同じような分岐がいくつものメソッドにある
構造
オブジェクトの集約版
ジェネリクス版
- 制限付き
- 静的にバインドするので実行時効率が良い
登場人物
Strategy
- 全アルゴリズム共通のインターフェースを定義
Concretestrategy
Context
concretestrategy
オブジェクトでカスタムできるstrategy
オブジェクトを保持- nullableにして、デフォルト動作を
Context
に実装する方法もある
- nullableにして、デフォルト動作を
Strategy
からデータアクセスするためのインターフェースを設けることも
クライアントコードからの利用
- クライアントは
concretestrategy
オブジェクトを選択・生成し、context
に渡す - 以降、
concretestrategy
オブジェクトを直接触ることはない context
はconcretestrategy
オブジェクトに処理を委譲する- 必要なデータだけ渡すパターン
context
丸ごと渡して、concretestrategy
側で必要なものを取得するパターン
結果
- 関連するアルゴリズムが1つのクラスツリーに切り出される
- ベースクラスに共通の処理を置くことができる
- 【補】Template Method Pattern
- ベースクラスに共通の処理を置くことができる
- 継承ではないアプローチである
- 条件分岐がなくなる
- ブラックボックスの実装を選択可能にできる
- クライアントは
Strategy
のバリエーションを知っている必要がある Strategy
とContext
の相互作用のオーバヘッドConcretestrategy
ごとに必要なパラメータが異なることがあるStrategy
のインターフェースは和集合的でなければならない- したがって、必要ない引数を生成し渡してしまうケースが出てくる
Concretestrategy
とContext
とを密結合にすることで回避可能
- オブジェクトの数が増える
Concretestrategy
に状態を持たせず、SingletonやFlyweightにすることで軽減可能
実装にあたり考えるべきこと
Context
とStrategy
のインターフェースConcretestrategy
はContext
から必要なデータを取得できる必要がある- 引数で渡す(push)
- 各
Concretestrategy
で必要なものの和集合になる - ので、無駄が生じうる
- 各
context
を丸ごと渡し、Concretestrategy
で必要なものを取得する(pull)- 無駄はなくなる
Context
とConcretestrategy
とが密結合してしまう
- 引数で渡す(push)
Strategy
をContext<Strategy>
のテンプレート型引数にするstrategy
オブジェクトをオプショナルにする- なければデフォルト動作、あれば処理を委譲
- 【所感】nullチェックが鬱陶しいので
DefaultStrategy
を用意したほうが良くないですか(Null Object Pattern)
関連するパターン
- Flyweight
- Singleton
- ともに、
Strategy
が状態をもたなければ適用可能
- ともに、
英語
- factor out
- 因数分解する
- 構成要素を取り除く
- 長くなりすぎた関数の一部を外に追い出すときなど
- refactorの一つの手段として factoring out がある