102、23种设计模式之装饰器模式(11/23)
一、定义
装饰器模式(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组件扩展等。