デコレーターパターン

2023年7月20日

デコレーションパターンは、既存のクラスに新しい機能を追加するために使用されるデザインパターンです。これは継承の代わりに組み合わせによって機能を追加します。以下に、C#言語を使用したデコレーションパターンのサンプルを示します。

サンプル

例として、コーヒーに対するデコレーションを考えてみましょう。最初に基本的なコーヒークラスを作成します。

// コーヒーインターフェース
public interface ICoffee
{
    string GetDescription();
    double GetCost();
}

// コーヒーインターフェースの実装クラス
public class SimpleCoffee : ICoffee
{
    public string GetDescription()
    {
        return "シンプルなコーヒー";
    }

    public double GetCost()
    {
        return 100.0;
    }
}

次に、デコレータクラスを作成します。デコレータクラスはICoffeeインターフェースを実装し、ICoffeeのインスタンスを保持します。

// デコレータクラス
public abstract class CoffeeDecorator : ICoffee
{
    protected ICoffee _coffee;

    public CoffeeDecorator(ICoffee coffee)
    {
        _coffee = coffee;
    }

    public virtual string GetDescription()
    {
        return _coffee.GetDescription();
    }

    public virtual double GetCost()
    {
        return _coffee.GetCost();
    }
}

そして、さまざまなトッピングを追加する具体的なデコレータクラスを作成します。

// ミルクトッピングクラス
public class MilkDecorator : CoffeeDecorator
{
    public MilkDecorator(ICoffee coffee) : base(coffee)
    {
    }

    public override string GetDescription()
    {
        return $"{base.GetDescription()}, ミルク";
    }

    public override double GetCost()
    {
        return base.GetCost() + 30.0;
    }
}

// シロップトッピングクラス
public class SyrupDecorator : CoffeeDecorator
{
    public SyrupDecorator(ICoffee coffee) : base(coffee)
    {
    }

    public override string GetDescription()
    {
        return $"{base.GetDescription()}, シロップ";
    }

    public override double GetCost()
    {
        return base.GetCost() + 50.0;
    }
}

これで、デコレーションパターンを使用してコーヒーにトッピングを追加することができます。

public static class Program
{
    public static void Main()
    {
        // シンプルなコーヒー
        ICoffee coffee = new SimpleCoffee();
        Console.WriteLine(coffee.GetDescription());
        Console.WriteLine($"価格: {coffee.GetCost()} 円");

        // ミルクトッピングを追加
        ICoffee coffeeWithMilk = new MilkDecorator(coffee);
        Console.WriteLine(coffeeWithMilk.GetDescription());
        Console.WriteLine($"価格: {coffeeWithMilk.GetCost()} 円");

        // シロップトッピングを追加
        ICoffee coffeeWithSyrup = new SyrupDecorator(coffee);
        Console.WriteLine(coffeeWithSyrup.GetDescription());
        Console.WriteLine($"価格: {coffeeWithSyrup.GetCost()} 円");

        // ミルクトッピングとシロップトッピングを追加
        ICoffee coffeeWithMilkAndSyrup = new SyrupDecorator(new MilkDecorator(coffee));
        Console.WriteLine(coffeeWithMilkAndSyrup.GetDescription());
        Console.WriteLine($"価格: {coffeeWithMilkAndSyrup.GetCost()} 円");
    }
}

結果

シンプルなコーヒー
価格: 100 円
シンプルなコーヒー, ミルク
価格: 130 円
シンプルなコーヒー, シロップ
価格: 150 円
シンプルなコーヒー, ミルク, シロップ
価格: 180 円

このように、デコレーションパターンを使うと、既存のクラスを拡張し、新しい機能を追加することができます。デコレータクラスは組み合わせることができるので、様々なトッピングを自由に追加できる柔軟性があります

UMLクラス図

  • ICoffee: コーヒーのインターフェースを表します。
  • SimpleCoffee: ICoffeeを実装する、シンプルなコーヒークラスを表します。
  • CoffeeDecorator: ICoffeeをデコレートするための抽象クラスを表します。
  • MilkDecorator: ICoffeeをミルクでデコレートするクラスを表します。
  • SyrupDecorator: ICoffeeをシロップでデコレートするクラスを表します。

矢印は、継承や実装の関係を示しています。

PlantUMLコードを解釈してダイアグラムを描画するツールを使用すると、上記のコードに基づいてデコレーションパターンのUMLダイアグラムが表示されます。ダイアグラムはクラスとその関連を視覚的に表現するためのものです。sh