Menu
Coddy logo textTech

Strategyパターン

CoddyのC#ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 55/70。

Strategy patternは、アルゴリズムのファミリーを定義し、それぞれを独自のクラスにカプセル化して、実行時に交換可能にする振る舞いパターンです。動作をハードコーディングする代わりに、目的の戦略をオブジェクトに注入します。

このパターンは3つの部分で構成されます。アルゴリズムの契約を定義する戦略 interface、異なる振る舞いを Implement する具体的な戦略 class、そして戦略を使用するコンテキスト class です。

public interface IPaymentStrategy
{
    void Pay(decimal amount);
}

public class CreditCardPayment : IPaymentStrategy
{
    public void Pay(decimal amount) => 
        Console.WriteLine($"Paid {amount} via Credit Card");
}

public class PayPalPayment : IPaymentStrategy
{
    public void Pay(decimal amount) => 
        Console.WriteLine($"Paid {amount} via PayPal");
}

public class ShoppingCart
{
    private IPaymentStrategy _paymentStrategy;
    
    public void SetPaymentMethod(IPaymentStrategy strategy)
    {
        _paymentStrategy = strategy;
    }
    
    public void Checkout(decimal total)
    {
        _paymentStrategy.Pay(total);
    }
}

コンテキスト(ShoppingCart)は、どの支払い方法を使用しているかを把握していません。提供された戦略に対して単にPay()を呼び出すだけです。

var cart = new ShoppingCart();

cart.SetPaymentMethod(new CreditCardPayment());
cart.Checkout(99.99m);  // クレジットカード経由で 99.99 を支払いました

cart.SetPaymentMethod(new PayPalPayment());
cart.Checkout(49.99m);  // PayPal 経由で 49.99 を支払いました

Strategy パターンは、複雑な条件分岐ロジックを排除します。新しい支払い方法を追加するには、IPaymentStrategyを実装する新しいクラスを作成するだけで、ShoppingCartを変更する必要はありません。これにより、コードは拡張に対して開かれ、変更に対して閉じた状態になります。

challenge icon

チャレンジ

簡単

Strategy パターンを使用して配送コスト計算機を構築しましょう。配送方法ごとに価格計算アルゴリズムが異なりますが、コアとなる注文処理ロジックを変更せずに、実行時にそれらを切り替えられるようにします。

コードを3つのファイルに整理します。

  • ShippingStrategy.cs: Shipping namespace 内に IShippingStrategy interface を Define し、double を返す CalculateCost(double weight) method を持たせます。次に、3つの Concrete な strategy class を Create します。
    • StandardShipping - コストを weight * 1.5 として計算
    • ExpressShipping - コストを weight * 3.0 + 5.0 として計算(定額の速達料金を含む)
    • OvernightShipping - コストを weight * 5.0 + 10.0 として計算(基本料金が高いプレミアムサービス)
  • OrderProcessor.cs: 同じ namespace 内に OrderProcessor class を Create します。これは shipping strategy を使用する Context class です。次の要素を持たせます。
    • 現在の IShippingStrategy を hold する private field
    • shipping strategy を変更するための SetShippingMethod(IShippingStrategy strategy) method
    • 現在の strategy を使用して配送コストを計算し、返す ProcessOrder(double weight) method
  • Program.cs: OrderProcessor を Create し、実行時に shipping strategy を交換する方法を示して、すべてをまとめます。同じ processor でも、strategy を変更するだけで異なるアルゴリズムを使用してコストを計算できます。

2つの入力を受け取ります。

  • 配送方法の種類: standardexpress、または overnight
  • 小数としての荷物の重量(例: 4.5

input type に基づいて appropriate な shipping strategy を設定した OrderProcessor を Create し、その後 order を処理して calculated cost を print します。

例えば、入力が express4.5 の場合、出力は次のようになります。

18.5

これは Strategy パターンの強力さを示しています。OrderProcessor 自体は配送コストの計算ロジックを一切持ちません。与えられた strategy に処理を委譲するだけなので、processor をまったく変更せずに新しい配送方法(DroneDelivery など)を簡単に追加できます。

自分で試してみよう

using System;
using Shipping;

class Program
{
    public static void Main(string[] args)
    {
        // 入力を読み取る
        string shippingType = Console.ReadLine();
        double weight = Convert.ToDouble(Console.ReadLine());

        // TODO: OrderProcessor のインスタンスを作成する

        // TODO: shippingType ("standard", "express", or "overnight") に基づいて、
        // 適切な配送戦略を作成し、プロセッサに設定する

        // TODO: 注文を処理し、計算されたコストを出力する
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: C#オンラインコンパイラ