Decorator (デコレータ)
装飾者
Decoratorパターンとは、サブクラス化せずにクラスの機能拡張を行うためのパターンです。その機能拡張は動的に行うことができます。イメージとしては共通の親クラスを持つ装飾されるクラスとデコレータを定義し、そのクラスをデコレータでラップしていく感じになります。
では、例を示します。
- 装飾されるクラスとデコレータの基本クラスとなる抽象クラスを定義します。
public abstract class AbstractFood
{
protected string description = "食品の説明";
public virtual string Description
{
get
{
return description;
}
}
public abstract decimal GetPrice();
}
- 1.で定義した抽象クラスを継承した、デコレータの基本クラスとなる派生抽象クラスを定義します。
public abstract class AbstractDecorator : AbstractFood
{
public abstract override string Description
{
get;
}
}
- 装飾される大元となるクラスを定義します。このクラスでは必要なメソッドをオーバーライドします。今回は牛丼クラスとして定義します。
public class Gyudon : AbstractFood
{
public Gyudon()
{
this.description = "牛丼";
}
public override decimal GetPrice()
{
return 380m;
}
}
- デコレータのクラスを定義します。デコレータでは、内部に被装飾者のフィールドを持ち、それぞれのメソッドの結果は被装飾者の同一名メソッドの実行結果に追加する形にします。今回は牛丼のトッピングとしてキムチとつゆだくを定義します。
class Kimuchi : AbstractDecorator
{
private AbstractFood food;
public Kimuchi(AbstractFood food)
{
this.food = food;
}
public override string Description
{
get
{
return food.Description + ",キムチ";
}
}
public override decimal GetPrice()
{
return food.GetPrice() + 100m;
}
}
class Tsuyudaku : AbstractDecorator
{
private AbstractFood food;
public Tsuyudaku(AbstractFood food)
{
this.food = food;
}
public override string Description
{
get
{
if ( food is Tsuyudaku )
{
return food.Description + "だく";
}
else
{
return food.Description + ",つゆだく";
}
}
}
public override decimal GetPrice()
{
return food.GetPrice() + 0;
}
}
以上のコードを実行してみます。
実行用コード
class Program
{
static void Main(string[] args)
{
AbstractFood order = new Gyudon();
Console.WriteLine("説明:{0}", order.Description);
Console.WriteLine("価格:{0:N} 円", order.GetPrice());
order = new Kimuchi(order);
Console.WriteLine("説明:{0}", order.Description);
Console.WriteLine("価格:{0:N} 円", order.GetPrice());
order = new Tsuyudaku(order);
Console.WriteLine("説明:{0}", order.Description);
Console.WriteLine("価格:{0:N} 円", order.GetPrice());
order = new Tsuyudaku(order);
Console.WriteLine("説明:{0}", order.Description);
Console.WriteLine("価格:{0:N} 円", order.GetPrice());
}
}
実行結果
説明:牛丼
価格:380.00 円
説明:牛丼,キムチ
価格:480.00 円
説明:牛丼,キムチ,つゆだく
価格:480.00 円
説明:牛丼,キムチ,つゆだくだく
価格:480.00 円
上記のように、大本となる牛丼にトッピングを追加していくと、その分説明、価格が変化することが確認できます。
さて、Decoratorパターンを実際に使うような状況ですが、業務アプリではあまりなさそうな気がしますね。パッケージアプリなら、図形の表示スタイルを表すのに使ったりしてそうですね。まさに「Decorate」しますし。
あ、でも一度に複数のところ(標準出力、ファイル、DBなど)にログを吐いたりする場合、これを使えばインスタンス一つで全部処理ができそうな感じがします。
こんな使い方ってあってます?