问题:
在面向对象系统的设计和开发中,在某些特定的场景下,需要在运行时不改变对象类的前提下动态的为已经定义好的对象添加新的职责(操作),使用继承时将会创建出大量的子类,而且继承的实现都是静态的,客户端不能在运行期(runtime)根据环境需要灵活控制改变组合添加的多个功能。
定义:
动态的给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更加灵活。
意图:
提供一个Decorator角色,它维护了一个需要装饰的Component具体对象的索引,Decorator收所有的来自客户端的请求,转发这些请求给Component之前或以后增加一些附加功能来装饰Component。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。Decorator继承了Component所具有的接口,所以我们可以使用一个或者多个Decorator对象来“装饰”一个Component对象,且装饰后的对象仍然是一个Component对象。
参与者:
•抽象组件(Component)角色:
一个抽象接口,是被装饰类和装饰类的父接口。装饰者和被装饰对象拥有共同一致的接口。
•具体组件(Concrete Component)角色:
具体需要被装饰的类,他实现了抽象组件接口。
•抽象装饰(Decorator)角色:
包含一个组件的引用,并定义了与抽象组件一致的接口。
•具体装饰(Concrete Decorator)角色:
为抽象装饰角色的实现类。负责具体的装饰。
UML:
实例说明:
诺基亚手机工厂
手机功能扩展不用修改或重新定义手机工厂,可以为手机装饰多个功能。
uml图如下:
代码:
/// 抽象组件接口,定义了装饰者和被装饰对象拥有共同一致的接口。
/// </summary>
public abstract class ComponentPhone
{
public abstract void ShowPhone();
}
/// <summary>
/// 具体装饰对象
/// </summary>
public class ComponentN8 : ComponentPhone
{
public override void ShowPhone()
{
System.Console.Write("我是N8手机。");
}
}
/// <summary>
/// 抽象装饰接口
/// </summary>
public class DecoratorPhone : ComponentPhone
{
ComponentPhone component;
public DecoratorPhone(ComponentPhone _component)
{
component = _component;
}
public override void ShowPhone()
{
if (component != null)
{
component.ShowPhone();
}
}
}
/// <summary>
/// 具体装饰类
/// </summary>
public class PhoneGPS : DecoratorPhone
{
public PhoneGPS(ComponentPhone _component)
: base(_component)
{
}
public override void ShowPhone()
{
base.ShowPhone();
this.ShowGPS();
}
/// <summary>
/// addedbehavior(),需要装饰到,被装饰对象中的方法
/// </summary>
public void ShowGPS()
{
System.Console.Write("我有GPS导航功能!");
}
}
/// <summary>
/// 具体装饰类
/// </summary>
public class PhoneHFR : DecoratorPhone
{
public PhoneHFR(ComponentPhone _component)
: base(_component)
{
}
public override void ShowPhone()
{
base.ShowPhone();
this.ShowHFR();
}
/// <summary>
/// addedbehavior(),需要装饰到,被装饰对象中的方法
/// </summary>
public void ShowHFR()
{
System.Console.Write("我有HFR人脸识别功能!");
}
}
/// <summary>
/// 客户端测试
/// </summary>
public void DecoratorTest()
{
ComponentN8 n8 = new ComponentN8();
DecoratorPhone gps = new PhoneGPS(n8);
DecoratorPhone hfr = new PhoneHFR(gps);
hfr.ShowPhone();
}
优点:
•比继承更灵活
从为对象添加功能的角度来看,装饰模式比继承来得更灵活。继承是静态的,而且一旦继承是所有子类都有一样的功能。而装饰模式采用把功能分离到每个装饰器当中,然后通过对象组合的方式,在运行时动态的组合功能,每个被装饰的对象,最终有哪些功能,是由运行期动态组合的功能来决定的。
•更容易复用功能
装饰模式把一系列复杂的功能,分散到每个装饰器当中,一般一个装饰器只实现一个功能,这样实现装饰器变得简单,更重要的是这样有利于装饰器功能的复用,可以给一个对象增加多个同样的装饰器,也可以把一个装饰器用来装饰不同的对象,从而复用装饰器的功能。
•简化高层定义
装饰模式可以通过组合装饰器的方式,给对象增添任意多的功能,因此在进行高层定义的时候,不用把所有的功能都定义出来,而是定义最基本的就可以了,可以在使用需要的时候,组合相应的装饰器来完成需要的功能。
缺点:
•会产生很多细粒度对象
装饰模式是把一系列复杂的功能,分散到每个装饰器当中,一般一个装饰器只实现一个功能,这样会产生很多细粒度的对象,而且功能越复杂,需要的细粒度对象越多。
应用情景:
•在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
•如果不合适使用子类来进行扩展的时候