本文へスキップ
BecomeCoder

C#デザインパターンコース · 第1章 デザインパターン · レッスン8

振る舞い①:Strategy / State

ブラウザで完結

導入

振る舞いに関するパターンは「オブジェクト間の処理の受け渡し」を工夫します。Strategyは「アルゴリズムを差し替え可能にする」、Stateは「状態に応じて振る舞いを変える」。どちらも巨大なif/switchを、差し替え可能なオブジェクトに置き換えます。

図解

flowchart LR
    C["コンテキスト"] --> S["Strategy(差し替え可能な処理)"]
    S --> S1["通常料金"]
    S --> S2["会員割引"]
    S --> S3["セール価格"]
    style S fill:#e1f5fe

サンプル

// Strategy: 料金計算アルゴリズムを外から差し替える
var cart = new Cart(new MemberDiscount());
Console.WriteLine(cart.Checkout(1000));   // 900

cart = new Cart(new NoDiscount());
Console.WriteLine(cart.Checkout(1000));   // 1000

interface IPricing { int Apply(int price); }
class NoDiscount : IPricing { public int Apply(int price) => price; }
class MemberDiscount : IPricing { public int Apply(int price) => price * 9 / 10; }

class Cart
{
    private readonly IPricing _pricing;
    public Cart(IPricing pricing) => _pricing = pricing;
    public int Checkout(int price) => _pricing.Apply(price);
}
  • Strategy: アルゴリズムをインターフェースにして、実行時に差し替える(前章のDIそのもの)
  • State: オブジェクトの内部状態をクラス化し、状態ごとに振る舞いを変える(信号機・注文ステータス等)
  • 巨大な条件分岐を「オブジェクトの差し替え」に変換するのが共通の狙い

演習

var calc = new Calculator(new AddStrategy());
Console.WriteLine(calc.Run(3, 4));   // 7

// TODO: IOperation(Do(int,int)→int)を実装する AddStrategy(加算)を定義してください
interface IOperation { int Do(int a, int b); }
class Calculator
{
    private readonly IOperation _op;
    public Calculator(IOperation op) => _op = op;
    public int Run(int a, int b) => _op.Do(a, b);
}
___
  • 期待される出力: 7
ヒント1を見る

class AddStrategy : IOperation { public int Do(int a, int b) => a + b; }

ヒント2を見る

戦略を差し替えればCalculator本体は無変更で動作が変わります

まとめ

  • Strategyはアルゴリズムを差し替え可能にする
  • Stateは状態ごとに振る舞いを切り替える
  • 巨大な条件分岐をオブジェクトの差し替えに置き換える

次回: 通知と仲介のObserver/Mediatorです。

実際に動かしてみよう

本文のサンプルや演習のコードは、コードブロック右上の「コピー」ボタンでコピーして、下のエディタに貼り付ければそのまま実行できます。

C# — ブラウザ内で実行

ブラウザ内でC#を動かす環境を読み込みます(初回のみ数秒)。
スクロールして表示された時点でも自動で読み込まれます。