一、定义
装饰器模式(Decorator Pattern)是一种结构型设计模式,允许在不修改原有类或继承体系的前提下,动态地为对象添加新功能。其核心思想是通过组合而非继承实现功能扩展,符合“开闭原则”(对扩展开放,对修改关闭)。
二、应用场景
1.动态扩展功能
需要运行时为对象灵活添加/移除功能,例如:
- 为文本编辑器动态添加字体、颜色、下划线等格式。
- 为咖啡店饮品动态添加配料(牛奶、糖浆等)。
2.避免继承导致的类爆炸
当继承会导致子类数量指数级增长时(如为每个功能组合创建子类),装饰器模式通过组合实现功能排列组合。
3.需要透明扩展的场景
客户端无需知道对象是否被装饰,接口保持一致(如Java IO流中的BufferedInputStream装饰FileInputStream)。
4.替代多层继承
如Android中为View动态添加边框、点击事件等,避免继承导致的层次过深。
三、优缺点
1.优点
- 灵活性高:动态添加/移除功能,无需修改原有代码。
- 避免类爆炸:通过组合实现功能扩展,减少子类数量。
- 符合开闭原则:对扩展开放,对修改关闭。
2.缺点
- 代码复杂度增加:多层装饰时,调试和追踪逻辑困难。
- 性能开销:多层装饰可能增加对象创建和调用的开销。
- 接口污染风险:装饰器需实现与被装饰对象相同的接口,可能暴露不必要的方法。
四、C# 示例代码
以下示例模拟为Person对象动态添加“红帽子”和“黑外套”装饰:
using System;
// 1. 定义组件接口
public interface IPerson
{
void Introduce();
}
// 2. 具体组件:原始对象
public class Person : IPerson
{
private string _name;
private int _age;
public Person(string name, int age)
{
_name = name;
_age = age;
}
public void Introduce()
{
Console.WriteLine($"我叫{_name},今年{_age}岁");
}
}
// 3. 抽象装饰器:持有组件引用
public abstract class PersonDecorator : IPerson
{
protected IPerson _person;
public PersonDecorator(IPerson person)
{
_person = person;
}
public virtual void Introduce()
{
_person.Introduce();
}
}
// 4. 具体装饰器:红帽子
public class PersonRedHatDecorator : PersonDecorator
{
public PersonRedHatDecorator(IPerson person) : base(person) { }
public override void Introduce()
{
base.Introduce();
Console.WriteLine("我有一顶红色的帽子");
}
}
// 5. 具体装饰器:黑外套
public class PersonBlackJacketDecorator : PersonDecorator
{
public PersonBlackJacketDecorator(IPerson person) : base(person) { }
public override void Introduce()
{
base.Introduce();
Console.WriteLine("我有一件黑色的外套");
}
}
// 6. 客户端代码
class Program
{
static void Main(string[] args)
{
// 原始对象
IPerson person = new Person("张三", 18);
person.Introduce();
Console.WriteLine("---------装饰上红帽子---------");
person = new PersonRedHatDecorator(person);
person.Introduce();
Console.WriteLine("---------装饰上黑外套---------");
person = new PersonBlackJacketDecorator(person);
person.Introduce();
}
}
输出结果:
我叫张三,今年18岁
---------装饰上红帽子---------
我叫张三,今年18岁
我有一顶红色的帽子
---------装饰上黑外套---------
我叫张三,今年18岁
我有一顶红色的帽子
我有一件黑色的外套
五、关键点总结
- 装饰器与被装饰对象实现相同接口,确保客户端代码无感知。
- 装饰器持有被装饰对象的引用,通过组合实现功能叠加。
- 支持多层装饰,如示例中先添加红帽子,再添加黑外套。
- 典型应用:Java IO流、ASP.NET Core中间件、GUI组件扩展等。