设计模式是可扩展且可维护的软件的基石。装饰器模式(Decorator Pattern)就是这样一种强大的模式,它属于结构型设计模式类别。如果你曾受困于继承的僵化性,或者遇到过需要扩展对象行为却又不想改变其核心结构的情况,那么装饰器模式就是你正在寻找的解决方案。
在本文中,我们将深入探究装饰器模式,探讨它的重要性,提供实际场景示例,并展示实用的C#代码示例。到本文结尾时,你将具备在自己的项目中有效应用装饰器模式的知识。
装饰器模式是一种结构型设计模式,它允许你在不改变对象结构的情况下动态地为对象添加新功能。它为扩展功能提供了一种比继承更灵活的替代方案。装饰器模式使用组合而非继承的方式——用另一个对象(装饰器)来包装一个对象,以此扩展其行为。
想象一家咖啡店,店里售卖基础咖啡,顾客可以添加牛奶、糖或者焦糖糖浆等配料。我们不用为每一种组合(例如,加奶咖啡、加糖加奶咖啡)都创建单独的子类,而是使用装饰器模式来动态地添加这些特性。
组件(ICoffee)
│
├── 具体组件(SimpleCoffee)
│
├── 抽象装饰器(CoffeeDecorator)
│
└── 具体装饰器
├── MilkDecorator
└── SugarDecorator
解释:
让我们使用C#逐步实现装饰器模式。
步骤1:定义组件接口
public interface ICoffee
{
string GetDescription();
double GetCost();
}
ICoffee
接口为基础对象(原味咖啡)和任何经过装饰的对象(添加了配料的咖啡)定义了通用操作(GetDescription
和GetCost
)。
步骤2:实现具体组件
public class SimpleCoffee : ICoffee
{
public string GetDescription()
{
return "Simple Coffee";
}
public double GetCost()
{
return 2.00; // 原味咖啡的基础价格
}
}
在这里,SimpleCoffee
是ICoffee
的具体实现。它代表没有任何添加配料的基础咖啡,提供了基础的描述和价格。
步骤3:定义抽象装饰器
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();
}
}
CoffeeDecorator
类实现了ICoffee
接口,并持有一个对ICoffee
对象的引用。它充当一个包装器,将方法调用转发给底层对象(_coffee
)。它是所有具体装饰器的基类。
步骤4:实现具体装饰器 牛奶装饰器
public class MilkDecorator : CoffeeDecorator
{
public MilkDecorator(ICoffee coffee) : base(coffee) { }
public override string GetDescription()
{
return _coffee.GetDescription() + ", Milk";
}
public override double GetCost()
{
return _coffee.GetCost() + 0.50;
}
}
糖装饰器
public class SugarDecorator : CoffeeDecorator
{
public SugarDecorator(ICoffee coffee) : base(coffee) { }
public override string GetDescription()
{
return _coffee.GetDescription() + ", Sugar";
}
public override double GetCost()
{
return _coffee.GetCost() + 0.20;
}
}
具体装饰器(MilkDecorator
和SugarDecorator
)扩展了CoffeeDecorator
类,并为咖啡添加特定的特性(牛奶和糖)。它们重写了GetDescription
和GetCost
方法,以修改基础咖啡的描述和价格。
步骤5:在客户端代码中使用装饰器模式
class Program
{
static void Main(string[] args)
{
ICoffee coffee = new SimpleCoffee();
Console.WriteLine($"{coffee.GetDescription()} costs {coffee.GetCost():C}");
coffee = new MilkDecorator(coffee);
Console.WriteLine($"{coffee.GetDescription()} costs {coffee.GetCost():C}");
coffee = new SugarDecorator(coffee);
Console.WriteLine($"{coffee.GetDescription()} costs {coffee.GetCost():C}");
}
}
输出:
Simple Coffee costs $2.00
Simple Coffee, Milk costs $2.50
Simple Coffee, Milk, Sugar costs $2.70
客户端代码使用装饰器动态地为一杯基础咖啡添加牛奶和糖。这展示了装饰器模式的灵活性,因为客户端可以按任意组合来使用装饰器。
装饰器模式是一种强大的工具,它能在不改变原始对象结构的情况下动态地扩展对象行为。它为继承提供了一种灵活的替代方案,并遵循开闭原则,使其成为软件开发人员工具包中的一种重要模式。通过使用装饰器模式,你可以以模块化的方式组合对象,避免复杂的继承层次结构。