1、简介

简要说明就是动态地给一个对象添加一些额外的职责。适用于需要扩展一个类的功能,或给一个类添加多个变化的情况。

装饰器,顾名思义就是在原有基础上添加一些功能。

装饰器模式中各个角色有:

        抽象构件(Component)角色:定义一个对象接口,可以给这些对象动态地添加一些职责。
        具体构件(ConcreteComponent)角色:定义了一个具体的对象,也可以给这个对象添加一些职责。
        抽象装饰类(Decorator)角色:持有一个构件(Component)对象的引用,并定义一个与抽象构件接口一致的接口。
        具体装饰类(ConcreteDecorator)角色:负责给构件对象“贴上”一些附加的职责。

2、适用场景

扩展一个类的功能:原有类无法修改或者修改困难的情况下,对类进行多次扩展或功能性比较相互独立,有效防止多次扩展的情况下子类的膨胀。

动态增加或撤销功能:需要动态地给对象添加或移除功能时。

多个功能组合:需要实现多个功能的不同组合时。

 3、举例说明

现在有一个手机,其仅有打电话的功能。现在需要给它加一个看视频和放音乐的功能。

传统做法如下:

手机类:

/// <summary>
/// 手机类
/// </summary>
public class Phone
{
    public void Call()
    {
        Console.WriteLine("打电话");
    }
}

增加功能:

public class FYY:Phone
{
    public void Install()
    {
        Console.WriteLine("放音乐!");
    }
}

public class FSP : Phone
{
    public void Install()
    {
        Console.WriteLine("放视频!");
    }
}

使用:

private void WTBtn_Click(object sender, EventArgs e)
{
    Phone phone0 = new Phone();//旧版手机
    phone0.Call();//仅有打电话的功能
    Console.WriteLine("\n");
    FYY phone = new FYY();//新版手机1
    phone.Call();//打电话,手机本来的功能
    phone.Install();//放音乐,给手机拓展的东西
    Console.WriteLine("\n");
    FSP phone1=new FSP();//新版手机2
    phone1.Call();//打电话,手机本来的功能
    phone1.Install();//放视频,给手机拓展的东西
}

C# 结构型设计模式----装饰器模式-LMLPHP

可以看出,每当需要增加一个功能,就需要增加一个子类。这种简单的单一功能问题还不大,当你既要放音乐又要放视频的功能的话,那你要不就是再实现一个之类去包含两种功能,要不就多重继承让放音乐的类继承放视频的类。这样实例化放音乐的类就能达到使用两种功能。当需要的功能越多,继承就越深,或者有重复方法的类就越多。但这显然不科学。 装饰器模式就能很好解决此类问题。

装饰器模式

 抽象构件(Component)角色

 /// <summary>
 /// 抽象构件角色(Component)
 /// </summary>
 public abstract class IPhone
 {
     public abstract void Call();
 }

具体构件(ConcreteComponent)角色

 /// <summary>
 /// 具体构件角色(Concrete Component)
 /// </summary>
 public class Phone : IPhone
 {
     public override void Call()
     {
         Console.WriteLine("打电话");
     }
 }

抽象装饰类(Decorator)角色

/// <summary>
/// 抽象装饰类(Decorator)角色
/// </summary>
public abstract class PhoneDecorator : IPhone
{
    protected IPhone Phone { get; }

    public PhoneDecorator(IPhone phone)
    {
        Phone = phone;
    }

    /// <summary>
    /// 可以定义新增的功能方法,也可以不定义,直接给Call方法添加装饰
    /// </summary>
    public abstract void Install();
}

具体装饰类(ConcreteDecorator)角色

 /// <summary>
 /// 具体装饰类(ConcreteDecorator)角色
 /// </summary>
 // 放音乐功能装饰器
 public class YYDecorator : PhoneDecorator
 {
     public YYDecorator(IPhone phone) : base(phone)
     {
     }

     public override void Call()
     {
         base.Phone.Call();
         RunYY();//也可以给打电话这件事添加放音乐的功能
     }

     public override void Install()
     {
         Console.WriteLine("安装音乐!");
     }

     public void RunYY()
     {
         Console.WriteLine("语音通话!");
     }
 }


 /// <summary>
 /// 具体装饰类(ConcreteDecorator)角色
 /// </summary>
 // 放音乐功能装饰器
 public class SPDecorator : PhoneDecorator
 {
     public SPDecorator(IPhone phone) : base(phone)
     {
     }

     public override void Call()
     {
         base.Phone.Call();
         RunSP();//也可以给打电话这件事添加视频通话的功能
     }

     public override void Install()
     {
         Console.WriteLine("安装视频!");
     }
     public void RunSP()
     {
         Console.WriteLine("视频通话!");
     }
 }

使用:

 private void WTBtn_Click(object sender, EventArgs e)
 {
      IPhone phone = new Phone();//初始手机
 phone.Call();//初始手机打电话
 Console.WriteLine("");

 PhoneDecorator phone1 = new YYDecorator(phone);//语音通话手机
 phone1.Install();//安装语音通话功能
 phone1.Call();//安装语音通话功能的手机打电话
 Console.WriteLine("");

 PhoneDecorator phone2 = new SPDecorator(phone);//视频通话手机
 phone2.Install();//安装视频通话功能
 phone2.Call();//安装视频通话功能的手机打电话
 Console.WriteLine("");

 PhoneDecorator phone3 = new SPDecorator(phone);//视频的手机
 phone3.Install();//安装视频功能
 phone3 = new YYDecorator(phone3);//语音的手机
 phone3.Install();//安装音乐功能
 phone3.Call();//双支持的手机再打电话
 }

C# 结构型设计模式----装饰器模式-LMLPHP

注意:Call()方法和Install()方法都是实现了装饰器,一个是给原本的功能前后添加功能段,一个是独立添加其他的功能。

可以看出使用装饰类如果需要实现组合配置,仅需要对像重新实例化即可,无需创建新的对象,和使用多重继承了。 若需要增加其他功能仅需要增加具体装饰类(ConcreteDecorator)角色即可。

最后:

优点:
1、灵活性:装饰器模式可以以动态的方式在运行时给对象增加额外的职责,而不需要在编译时决定添加哪些功能。通过使用装饰器模式,可以在不改变原始对象结构的情况下,根据需要灵活地扩展对象的行为。
2、可插拔:通过使用装饰器模式,可以将功能分解成一系列的装饰器类,使得代码更加模块化和易于维护。可以在运行时动态地组合和替换装饰器对象,从而改变对象的行为。
3、可扩展性:装饰器模式可以避免继承带来的类膨胀问题,因为你可以通过组合装饰器对象来扩展对象的行为,而不是通过继承来添加新的功能。
4、符合开闭原则:装饰器模式完全遵守开闭原则,即对扩展开放,对修改封闭。通过使用装饰器模式,可以方便地添加新的装饰器类来扩展对象的行为,而不需要修改原始对象的代码。

缺点:
1、代码量增加:装饰器模式需要创建很多小类,即使只添加一个功能,也要额外创建一个类,这会使得程序更复杂。
2、增加代码复杂度:使用装饰器模式不但需要实例化组件,还要把组件包装到装饰者中,这会增加代码的复杂度。
3、设计难度高:装饰器模式需要对系统进行全面理解,设计出结构良好的装饰器类和被装饰类,才能够达到预期的效果。
4、性能问题:由于装饰器模式需要在运行时动态地创建对象和调用方法,这可能会导致性能上的问题。

注意:过度使用装饰器模式可能会导致程序变得复杂,增加系统中类的数量,并可能产生大量小粒度对象,使得代码变得难以维护。因此,在使用装饰器模式时需要谨慎考虑设计是否合适。

10-31 09:27