装饰模式的核心在于,它允许在不改变对象自身的基础上,在运行时向对象添加新的职责。这是通过创建一个包含原始对象的特殊包装对象(即装饰器)来实现的。装饰器类遵循与原始对象相同的接口,并在调用原始对象的方法之前或之后添加额外的行为。
装饰模式通常由以下几个角色组成:
装饰模式的优点包括:
装饰模式的缺点包括:
装饰模式在.NET框架中也有广泛的应用,例如在IO流的处理中,StreamReader
和StreamWriter
就是Stream
的装饰器,它们提供了缓冲和字符处理的功能。通过这种方式,.NET框架能够提供高度灵活和可扩展的读写功能。
假设我们有一个咖啡店的订单系统,我们需要能够动态地给咖啡添加各种配料,比如牛奶、糖、奶泡等。
首先,我们定义咖啡的组件接口:
C#// 组件接口
public interface ICoffee
{
string GetDescription();
double GetCost();
}
然后,我们实现具体的咖啡类型:
C#// 具体组件
public class PlainCoffee : ICoffee
{
public string GetDescription()
{
return "Plain Coffee";
}
public double GetCost()
{
return 1.0;
}
}
接下来,我们创建一个装饰器抽象类:
C#// 装饰抽象类
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();
}
}
现在,我们可以创建具体的装饰类:
C#// 具体装饰类:牛奶
public class MilkDecorator : CoffeeDecorator
{
public MilkDecorator(ICoffee coffee) : base(coffee) { }
public override string GetDescription()
{
return base.GetDescription() + ", with Milk";
}
public override double GetCost()
{
return base.GetCost() + 0.5;
}
}
C#// 具体装饰类:糖
public class SugarDecorator : CoffeeDecorator
{
public SugarDecorator(ICoffee coffee) : base(coffee) { }
public override string GetDescription()
{
return base.GetDescription() + ", with Sugar";
}
public override double GetCost()
{
return base.GetCost() + 0.2;
}
}
最后,我们可以使用装饰模式来创建订单:
C#public class Program
{
public static void Main()
{
ICoffee coffee = new PlainCoffee();
Console.WriteLine($"{coffee.GetDescription()} Cost: ${coffee.GetCost()}");
// 添加牛奶
coffee = new MilkDecorator(coffee);
Console.WriteLine($"{coffee.GetDescription()} Cost: ${coffee.GetCost()}");
// 再添加糖
coffee = new SugarDecorator(coffee);
Console.WriteLine($"{coffee.GetDescription()} Cost: ${coffee.GetCost()}");
}
}
在这个例子中,我们首先创建了一个简单的咖啡对象,然后通过添加装饰器(牛奶和糖)来增加额外的功能(调料),同时每次装饰都会影响咖啡的最终成本。这种方式使得我们可以动态地、不限次数地添加新的装饰器,而不需要修改现有的类。
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!