#21 / 23
B振る舞いDIFF
ストラテジー
Strategy
ナビアプリの『徒歩 / 車 / 電車』切替。同じ目的地に対し、別のアルゴリズムを実行時に差し込む。
Intent · 目的
目的は同じだけれど解き方が複数あるアルゴリズム群を、共通I/F の下にカプセル化して、利用側から1つ選んで差し込めるようにする。
Motivation · 動機
ECサイトの価格計算。一般会員は定価、メンバーは10%引き、VIPは30%引き、年末セール期間は別ロジック…と、`if 会員種別 == ...` を計算メソッドの中に書き始めると、ロジックが膨らむほど読めなくなる。Strategy なら『価格計算の戦略』を1つの抽象として切り出して、Cart は今アクティブな戦略に「計算して」と頼むだけ。新しい割引ロジックを足したい? クラス(または関数)を1個追加するだけ ── Cart には触らない。
適用場面
- 1同じ目的に対し、複数の解法・実装方式を実行時に切り替えたい場合。
- 2if/switch でアルゴリズムを選んでいる箇所を、もっと綺麗にしたい場合。
- 3テストでアルゴリズムを差し替えたい(モックや決定論的な実装にしたい)。
概念図
サンプルコード
type PricingStrategy = (base: number) => number;
const regular: PricingStrategy = b => b;
const member: PricingStrategy = b => Math.floor(b * 0.9);
const vip: PricingStrategy = b => Math.floor(b * 0.7);
class Cart {
constructor(private strategy: PricingStrategy = regular) {}
setStrategy(s: PricingStrategy){ this.strategy = s; }
total(base: number){ return this.strategy(base); }
}
const c = new Cart();
c.setStrategy(vip);
console.log(c.total(1000)); // 700Pros · メリット
- +アルゴリズムの追加・差し替えが容易で、本体クラスは触らない。
- +アルゴリズム1個ずつテストできる。
- +if/switch の塊が消え、読みやすい平らなコードになる。
Cons · デメリット
- −アルゴリズムが2〜3種類しかなく、増える予定もないなら、ただの遠回り。
- −クライアントがどの戦略を使うか知っている必要がある(普通は DI やファクトリで補完)。
- −戦略間で『同じ前処理』が必要な場合、どこに置くか悩ましい。
関連パターン
⚔ ready to test
理解度を確かめる時間だ
3 問のクイズで、 このパターンを身体に染み込ませよう。