模式介绍
装饰器模式试图向现有对象添加新的功能,而不改变该对象的定义。
换句话说,它希望向对象的单个实例添加新的职责,而不向对象类添加这些职责。
示例
想象一下,我们在一个farm-to-table餐馆。这个餐馆只售卖来自农场种植的蔬菜。但是有的时候,某种蔬菜暂时没有了,我们需要通知用户。
我们来模拟一下:
首先我们创建菜肴
/// <summary>
/// The abstract Component class
/// </summary>
abstract class RestaurantDish
{
public abstract void Display();
}
具体的菜肴实现(沙拉与面食)
/// <summary>
/// A ConcreteComponent class
/// </summary>
class FreshSalad : RestaurantDish
{
private string _greens;
private string _cheese; //I am going to use this pun everywhere I can
private string _dressing;
public FreshSalad(string greens, string cheese, string dressing)
{
_greens = greens;
_cheese = cheese;
_dressing = dressing;
}
public override void Display()
{
Console.WriteLine("
Fresh Salad:");
Console.WriteLine(" Greens: {0}", _greens);
Console.WriteLine(" Cheese: {0}", _cheese);
Console.WriteLine(" Dressing: {0}", _dressing);
}
}
/// <summary>
/// A ConcreteComponent class
/// </summary>
class Pasta : RestaurantDish
{
private string _pastaType;
private string _sauce;
public Pasta(string pastaType, string sauce)
{
_pastaType = pastaType;
_sauce = sauce;
}
public override void Display()
{
Console.WriteLine("
Classic Pasta:");
Console.WriteLine(" Pasta: {0}", _pastaType);
Console.WriteLine(" Sauce: {0}", _sauce);
}
}
构建一个装饰器类
/// <summary>
/// The abstract Decorator class.
/// </summary>
abstract class Decorator : RestaurantDish
{
protected RestaurantDish _dish;
public Decorator(RestaurantDish dish)
{
_dish = dish;
}
public override void Display()
{
_dish.Display();
}
}
具体的装饰器实现
/// <summary>
/// A ConcreteDecorator. This class will impart "responsibilities" onto the dishes
/// (e.g. whether or not those dishes have enough ingredients left to order them)
/// </summary>
class Available : Decorator
{
public int NumAvailable { get; set; } //How many can we make?
protected List<string> customers = new List<string>();
public Available(RestaurantDish dish, int numAvailable) : base(dish)
{
NumAvailable = numAvailable;
}
public void OrderItem(string name)
{
if (NumAvailable > 0)
{
customers.Add(name);
NumAvailable--;
}
else
{
Console.WriteLine("
Not enough ingredients for " + name + "'s order!");
}
}
public override void Display()
{
base.Display();
foreach(var customer in customers)
{
Console.WriteLine("Ordered by " + customer);
}
}
}
客户端调用:
static void Main(string[] args)
{
//Step 1: Define some dishes, and how many of each we can make
FreshSalad caesarSalad = new FreshSalad("Crisp romaine lettuce", "Freshly-grated Parmesan cheese", "House-made Caesar dressing");
caesarSalad.Display();
Pasta fettuccineAlfredo = new Pasta("Fresh-made daily pasta", "Creamly garlic alfredo sauce");
fettuccineAlfredo.Display();
Console.WriteLine("
Making these dishes available.");
//Step 2: Decorate the dishes; now if we attempt to order them once we're out of ingredients, we can notify the customer
Available caesarAvailable = new Available(caesarSalad, 3);
Available alfredoAvailable = new Available(fettuccineAlfredo, 4);
//Step 3: Order a bunch of dishes
caesarAvailable.OrderItem("John");
caesarAvailable.OrderItem("Sally");
caesarAvailable.OrderItem("Manush");
alfredoAvailable.OrderItem("Sally");
alfredoAvailable.OrderItem("Francis");
alfredoAvailable.OrderItem("Venkat");
alfredoAvailable.OrderItem("Diana");
alfredoAvailable.OrderItem("Dennis"); //There won't be enough for this order.
caesarAvailable.Display();
alfredoAvailable.Display();
Console.ReadKey();
}
总结
装饰器模式试图在运行时动态地向对象的实例添加功能,而不需要更改实例类的定义。
这对于某些场景特别有用,比如同一对象的不同实例可能表现不同的行为。
源代码
https://github.com/exceptionnotfound/DesignPatterns/tree/master/Decorator
原文
https://www.exceptionnotfound.net/decorator-the-daily-design-pattern/