LoginSignup
0
0

More than 1 year has passed since last update.

Decoratorパターン

Posted at

概要

デザインパターンの一つ、Decorotorパターンの具体例。
Decorotorパターンは名前の通り、具体化クラスをDecoratorクラスで次々とデコレーションできる。

書籍AdaptiveCodeの単一責務の原則で紹介されていたが、フレームワークのみで特定用途を示すものがなかったので取り上げてみた。

参照コード

wikipediaのDecorotorパターンはJavaだったので、GPTでC#にしてもらい、投稿主がコメントを追加したもの。

example.cs
/** 価格をあらわすインタフェース */
interface IPrice
{
    int GetValue();
}

/** 原価を表すクラス */
class PrimePrice : IPrice
{
    private int value;

    public PrimePrice(int value)
    {
        this.value = value;
    }

    public int GetValue()
    {
        return this.value;
    }
}

/** マージンを介する価格 */
abstract class MarginPrice : IPrice
{
    protected IPrice originalPrice;

    public MarginPrice(IPrice price)
    {
        this.originalPrice = price;
    }

    public abstract int GetValue();
}

/** 設定された利益を仕入れ価格に上乗せする Price */
class WholesalePrice : MarginPrice
{
    private int advantage;

    public WholesalePrice(IPrice price, int advantage) : base(price)
    {
        this.advantage = advantage;
    }

    public override int GetValue()
    {
        return this.originalPrice.GetValue() + advantage;
    }
}

/** 仕入れ価格の 2 倍の値段を提示する Price */
class DoublePrice : MarginPrice
{
    public DoublePrice(IPrice price) : base(price)
    {
    }

    public override int GetValue()
    {
        return this.originalPrice.GetValue() * 2;
    }
}

class DecoratorTest
{
    static void Main(string[] args)
    {
        //PrimePriceをどんどんデコってる
        Console.WriteLine(
            new WholesalePrice(
                new DoublePrice(
                    new WholesalePrice(
                        new DoublePrice(
                            new PrimePrice(120)//valueが120のPrimePrice型のインスタンス
                        ), //GetValue()の返り値が240になるDoublePrice型のインスタンス
                        80
                    )//240+80=320
                ), //320*2=640
                200
            ).GetValue()
        );
    }
}
出力
840

クラス図

スクリーンショット 2023-04-09 10.47.09.png

ポイント

Decoratorクラス(DoublePrice、WholesalePrice)がIPrice型の参照をフィールドで持つ点がポイント。
それにより一回目のデコレーションでは具体化クラス(PrimePrice)のインスタンスを、二回目以降はひとつ前のDecoratorクラスのインスタンスを、それぞれコンストラクタで受け取れる。

SOLID原則

参照コードが原則を守っているかいくつか取り上げる

単一責務の原則

コード内の5つのクラスは依存関係が強く、1つのクラスにまとめられていてもおかしくない。
Decoratorパターンを使うことでクラスを最小化できている。

オープンクローズドの原則

機能追加にオープンで、機能追加しても既存のクラスは変更する必要がないためクローズド。
例えば消費税を価格に上乗せする機能が仕様追加された場合、下記の新クラスを追加するだけ。

example.cs
class TaxIncludedPrice : MarginPrice
{
    public TaxIncludedPrice(IPrice price) : base(price)
    {
    }

    /** 仕入れ価格の 1.1倍の値段にして消費税を加える */
    public override int GetValue()
    {
        var price = this.originalPrice.GetValue();
        return (int)(price * 1.1f);
    }
}

スクリーンショット 2023-04-09 10.47.40.png

リスコフの置換原則

継承先のDoublePriceやWholesalePriceで新しくメソッド定義されてないので守られている。

関連URL

C#で学ぶデザインパターン入門 ⑫Decorator Pattern

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0