概要
デザインパターンの一つ、Decorotorパターンの具体例。
Decorotorパターンは名前の通り、具体化クラスをDecoratorクラスで次々とデコレーションできる。
書籍AdaptiveCodeの単一責務の原則で紹介されていたが、フレームワークのみで特定用途を示すものがなかったので取り上げてみた。
参照コード
wikipediaのDecorotorパターンはJavaだったので、GPTでC#にしてもらい、投稿主がコメントを追加したもの。
/** 価格をあらわすインタフェース */
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
クラス図
ポイント
Decoratorクラス(DoublePrice、WholesalePrice)がIPrice型の参照をフィールドで持つ点がポイント。
それにより一回目のデコレーションでは具体化クラス(PrimePrice)のインスタンスを、二回目以降はひとつ前のDecoratorクラスのインスタンスを、それぞれコンストラクタで受け取れる。
SOLID原則
参照コードが原則を守っているかいくつか取り上げる
単一責務の原則
コード内の5つのクラスは依存関係が強く、1つのクラスにまとめられていてもおかしくない。
Decoratorパターンを使うことでクラスを最小化できている。
オープンクローズドの原則
機能追加にオープンで、機能追加しても既存のクラスは変更する必要がないためクローズド。
例えば消費税を価格に上乗せする機能が仕様追加された場合、下記の新クラスを追加するだけ。
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);
}
}
リスコフの置換原則
継承先のDoublePriceやWholesalePriceで新しくメソッド定義されてないので守られている。