コンテンツにスキップ

Strategy

個人的重要度と感想

★★★★★

処理や計算ロジックを外部に委託する感じ。

if 文の分岐を無くせるという点で有用だと思う。例ではインターフェースとクラスを使っているが、現代のプログラミングだと以下のように匿名関数(lambda 式、アロー関数)を使うほうが多いような気がする。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
type DiscountStrategy = (price: number) => number;

class ShoppingCart {
  calculateFinalPrice(
    originalPrice: number,
    discountStrategy: DiscountStrategy
  ) {
    return discountStrategy(originalPrice);
  }
}

const cart = new ShoppingCart();

console.log(
  "割引なし",
  cart.calculateFinalPrice(100, (price) => price) // 第2引数がStrategyパターンになっている
); // 割引なし 100

console.log(
  "固定料減額",
  cart.calculateFinalPrice(100, (price) => price - 10)
); // 固定料減額 90

console.log(
  "割引",
  cart.calculateFinalPrice(100, (price) => price * 0.85)
); // 割引 85

もしこのパターンを知らない場合、以下のようにひたすら if 文を分岐させることになる。バリエーションが増えるとどんどん長くなる。他のメソッドでも同じことをやることになると爆発する。if 文の実装漏れがあるとバグが出る。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class ShoppingCart {
  calculateFinalPrice(originalPrice: number, discountStrategy: string) {
    if (discountStrategy === "noDiscount") {
      return originalPrice;
    }
    if (discountStrategy === "fixedAmountDiscount") {
      return originalPrice - 10;
    }
    if (discountStrategy === "percentageDiscount") {
      return originalPrice * 0.85;
    }
  }
}

const cart = new ShoppingCart();

console.log("割引なし", cart.calculateFinalPrice(100, "noDiscount")); // 割引なし 100

console.log("固定料減額", cart.calculateFinalPrice(100, "fixedAmountDiscount")); // 固定料減額 90

console.log("割引", cart.calculateFinalPrice(100, "percentageDiscount")); // 割引 85

WebSocket では JSON をやり取りして、受信側は JSON の中身によって処理を分岐したりするが、そういうときに Strategy パターンを使えればいいのになと思うことがある。しかし JSON は文字列であり、パースしてもメソッドを持たないオブジェクトであるため、Strategy パターンを導入することはできない気がする。残念ながら外部のクラスなり関数なりが if 文なり辞書なりで処理を分岐してやらないといけないと思う。