前言
这里先举两个生活中的小栗子:
- 新房的装修,房屋装修并没有改变房屋居住的本质,但可以让房屋变得更漂亮,更温馨,更实用,更满足居家需求。
- 穿搭衣服,你可以根据天气气候变化,选择穿毛衣,穿羽绒服。也可以根据出行场合选择西装等等。
在软件设计中,类似上面的场景我们也可以把对象在不改变结构的情况下对其加工扩展修饰,使得对象具有更加强大的功能,这种技术在设计模式中就叫装饰模式。装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为。
装饰模式定义
装饰模式:动态地给一个对象增加一些额外的职责。就扩展功能面言,装饰模式提供了—种比使用子类更加灵活的替代方案。
装饰模式是一种结构型设计模式, 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。
代码实现
类图结构
标准的装饰模式应该包含如下4个角色(也可根据实际情况定义):
- Componcnt(抽象构建):它是具体构建和抽象装饰类的共同父类,声明了在具体构件中实轰的业务方法,它的引入可以使客户以一致的方式处理未被装饰的对象以及装饰之后的对象。
- ConcreteComponent(具体构建):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象物件中声明的方法,装饰类可以给它增加额外的职责(方法)。
- Decorater(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责通常在其子类中实现,它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子面扩展该方法,以达到装饰的目的。
- ConcerteDecorater(具体装饰类):它也是抽象装饰类的子类,负责向构建添加新的职责,每一个具体装饰类都定义了一系列新的行为,它可以调用再抽象装饰类中定义的方法,并且可以增加新的方法,以实现扩展对象的行为。
装饰模式的实现
- 抽象构建类,一般设计为抽象类或者接口,在其中声明抽象的业务方法,也可以在抽象构建中实现一些共有的业务方法。
- 具体构建类,继承抽象构建类,一般用作提供基本功能的实现
- 抽象装饰类,抽象模式的核心也就在这里,其典型代码如下
public class Decorator : Person
{
private readonly Person _person;
public Decorator(Person person)
{
_person = person;
}
public override void Show()
{
if (_person != null)
{
_person.Show();
}
}
}
- 具体装饰类,继承抽象装饰类,可以在此对其进行扩展,例如
public class ConcernTshirt : Decorator
{
public ConcernTshirt(Person person) : base(person)
{
}
public override void Show()
{
base.Show();
Console.WriteLine("T恤");
Necktie();
}
private void Necktie()
{
Console.WriteLine("领带");
}
}
优点和缺点以及使用场景
优点
- 扩展性:无需创建新子类即可扩展对象的行为
- 任意组装:可以用多个装饰封装对象来组合几种行为
- 可维护性:可以将同行为的一个大类拆分成多个较小的类
缺点
- 各层初始化配置看起来有点糟糕
- 因为可以随意装配,也就意味着顺序可能不那么同一,易于出错,排错也困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为繁琐
使用场景
- 如果希望在无需修改代码的情况下即可使用对象,且希望在运行时为对象新增额外的行为,可以使用装饰模式。
- 如果用继承来扩展对象行为的方案难以实现或者根本不可行, 你可以使用该模式。