基础介绍:

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

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

  大家都只知道如果想单纯的给原有类增加一些功能,可以直接继续该类生成一个子类就可以。

  举个例子,如果现在有个手机类,想给手机贴膜,传统的做法就是新建一个手机类的子类(手机贴膜子类),继承自手机类。

  使用这个子类就可以完成对手机的贴膜操作。

  那如果又想给手机按保护壳的话,传统做法有两种,可以继续新建一个手机类的子类(手机保护壳子类),继承自手机类。

  使用这个子类可以给手机按保护壳,但也就失去了给手机贴膜的功能。另一种做法,新建一个手机贴膜类的子类(手机贴膜+保护壳),也就是手机类的子子类。

  这样即可以贴膜也可以按手机壳。

  大家思考一个问题,如果有很多个装饰并且想随意组合的话,那就有N个子类并且存在很深的继承链路。

  想要解决这个问题,就可以用到装饰器了。

  比如贴膜装饰、保护壳装饰、贴纸装饰等等,它们都是独立存在的,只继承自装饰器类。

  什么意思呢?就是说给手机贴膜的时候它并不会给手机按保护壳的功能,职责单一,贴膜装饰器只负责给手机贴膜。

  这样做有什么好处呢?好处就是这些装饰可以随意组合,比如即想贴膜又想按保护壳,就可以将贴膜装饰+保护壳装饰进组组合。

  

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

  • 抽象构件(Component)角色:规范手机的构成
  • 具体构件(ConcreteComponent)角色:继承自抽象构件,具体实现手机。(大多情况下,可以省略抽象构件,抽象装饰类可以直接继承)
  • 抽象装饰类(Decorator)角色:创建一个构件(Component)对象的实例,可以使用这个实例调用原构件的功能,并规范装饰类。
  • 具体装饰类(ConcreteDecorator)角色:继承自抽象装饰类,具体实现该装饰功能。

应用场景:

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

  注:如果类的扩展比较简单,并且不会多次进行扩展的情况下直接使用类的继承生成子类的方式更为方便快捷。

创建方式:

  为了方便说明,以下实例就不创建抽象构件了。

  1. 首先先看下不使用装饰器进行类的扩展

     1     /// <summary>
    2 /// 手机类
    3 /// </summary>
    4 public class Phone
    5 {
    6 public void Print()
    7 {
    8 Console.WriteLine("手机");
    9 }
    10 }
    11
    12 /// <summary>
    13 /// 手机贴膜
    14 /// </summary>
    15 public class Sticker : Phone
    16 {
    17 public Sticker()
    18 {
    19 base.Print();
    20 }
    21
    22 /// <summary>
    23 /// 进行贴膜
    24 /// </summary>
    25 public void AddSticker()
    26 {
    27 Console.WriteLine("给手机贴膜");
    28 }
    29 }
    30
    31 /// <summary>
    32 /// 手机保护壳
    33 /// </summary>
    34 public class ProtectiveCase : Phone
    35 {
    36 public ProtectiveCase()
    37 {
    38 base.Print();
    39 }
    40
    41 /// <summary>
    42 /// 按保护壳
    43 /// </summary>
    44 public void AddProtectiveCase()
    45 {
    46 Console.WriteLine("给手机按保护壳");
    47 }
    48 }
    49
    50 /// <summary>
    51 /// 即贴膜又按保护壳
    52 /// </summary>
    53 public class ProtectiveCaseAndSticker : Sticker
    54 {
    55 public ProtectiveCaseAndSticker()
    56 {
    57 }
    58
    59 /// <summary>
    60 /// 按保护壳
    61 /// </summary>
    62 public void AddProtectiveCase()
    63 {
    64 Console.WriteLine("给手机按保护壳");
    65 }
    66 }
    67
    68 /// <summary>
    69 /// 客户端
    70 /// </summary>
    71 class Client
    72 {
    73 static void Main(string[] args)
    74 {
    75 //创建一个手机
    76 Phone phone = new Phone();
    77 phone.Print();
    78 Console.WriteLine("\r\n");
    79
    80 //给手机贴膜
    81 Sticker sticker = new Sticker();
    82 sticker.AddSticker();
    83 Console.WriteLine("\r\n");
    84
    85 //给手机按保护壳
    86 ProtectiveCase protectiveCase = new ProtectiveCase();
    87 protectiveCase.AddProtectiveCase();
    88 Console.WriteLine("\r\n");
    89
    90 //即贴膜又按保护壳
    91 ProtectiveCaseAndSticker protectiveCaseAndSticker = new ProtectiveCaseAndSticker();
    92 protectiveCaseAndSticker.AddSticker();
    93 protectiveCaseAndSticker.AddProtectiveCase();
    94 Console.ReadKey();
    95 }
    96 }

    通过上述实例可以看出,如果各个扩展功能比较独立的话可以直接进行继承扩展。

    如果各个功能直接有交集的情况下,会造成很深的继承关系。

    比如上述实例中,如果单独贴膜或者单独安装保护壳则直接继承手机类即可。

    但如果想要即贴膜又要安装保护壳,各自继承手机类的方式就行不通了,只能在贴膜类或者保护壳类的基础上进行扩展。

    如果还有添加手机挂饰,那就还需要再一层继承关系。

    要解决这个问题就用到了装饰器,下面看看使用装饰器是怎么给手机添加新功能的。

  2. 使用装饰器模式对类进行扩展

     1     /// <summary>
    2 /// 手机类
    3 /// </summary>
    4 public class Phone
    5 {
    6 public void Print()
    7 {
    8 Console.WriteLine("手机");
    9 }
    10 }
    11
    12 /// <summary>
    13 /// 装饰抽象类
    14 /// </summary>
    15 public abstract class Decorator : Phone
    16 {
    17 private Phone phone;
    18
    19 public Decorator(Phone p)
    20 {
    21 this.phone = p;
    22 }
    23
    24 public abstract void AddDecorator();
    25 }
    26
    27 /// <summary>
    28 /// 贴膜装饰
    29 /// </summary>
    30 public class Sticker : Decorator
    31 {
    32 public Sticker(Phone p)
    33 : base(p)
    34 {
    35 }
    36
    37 public override void AddDecorator()
    38 {
    39 Console.WriteLine("给手机贴膜");
    40 }
    41 }
    42
    43 /// <summary>
    44 /// 保护壳装饰
    45 /// </summary>
    46 public class ProtectiveCase : Decorator
    47 {
    48 public ProtectiveCase(Phone p)
    49 : base(p)
    50 {
    51 }
    52
    53 /// <summary>
    54 /// 按保护壳
    55 /// </summary>
    56 public override void AddDecorator()
    57 {
    58 Console.WriteLine("给手机按保护壳");
    59 }
    60 }
    61
    62 /// <summary>
    63 /// 客户端
    64 /// </summary>
    65 class Client
    66 {
    67 static void Main(string[] args)
    68 {
    69 //单独给手机贴膜
    70 Phone phone = new Phone();
    71 phone.Print();
    72 Decorator sticker = new Sticker(phone);
    73 sticker.AddDecorator();
    74
    75 //单独给手机按保护壳
    76 phone = new Phone();
    77 phone.Print();
    78 Decorator protectiveCase = new ProtectiveCase(phone);
    79 protectiveCase.AddDecorator();
    80 Console.WriteLine("\r\n");
    81
    82 //即贴膜又按保护壳
    83 phone = new Phone();
    84 phone.Print();
    85 //首先创建贴膜装饰实例,将手机对象传入
    86 Decorator decorator = new Sticker(phone);
    87 //进行贴膜操作
    88 decorator.AddDecorator();
    89 //创建保护壳装饰实例,将贴膜后的手机对象传入
    90 decorator = new ProtectiveCase(decorator);
    91 //进行按保护壳操作
    92 decorator.AddDecorator();
    93 Console.ReadKey();
    94 }
    95 }

    从上述实例中可以看出,各个装饰类只对装饰抽象类负责,职责单一。

    各个装饰进行组合时,方便随意。新增装饰时,只需要新增一个继承自装饰抽象类的子类即可实现以原有装饰的随意组合使用。

总结:

  想要扩展一个类的时候,传统的继承生成子类的形式,适用于扩展简单,并且不会多次扩展的情况下。

  而如果一个类的扩展是周期性,多次扩展的或功能性比较相互独立的情况下,可以使用装饰器,可以有效的解决传统继承扩展子类膨胀的问题。

  装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

  

  

c#装饰器模式详解的更多相关文章

  1. (十)装饰器模式详解(与IO不解的情缘)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...

  2. 涉及模式之 装饰器模式详解(与IO不解的情缘)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...

  3. Java 装饰器模式详解

    转载请注明出处:http://blog.csdn.net/zhaoyanjun6/article/details/56488020 前言 在上面的几篇文章中,着重介绍了Java 中常见的 IO 相关知 ...

  4. Javascript设计模式之装饰者模式详解篇

    一.前言: 装饰者模式(Decorator Pattern):在不改变原类和继承的情况下动态扩展对象功能,通过包装一个对象来实现一个新的具有原对象相同接口的新的对象. 装饰者模式的特点: 1. 在不改 ...

  5. 【装饰器设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

    简介 装饰器模式(Decorator Pattern)是一种结构型设计模式.将对象放入到一个特殊封装的对象中,为这个对象绑定新的行为,具备新的能力,同时又不改变其原有结构. 如果你希望在无需修改代码的 ...

  6. python装饰器大详解

    1.作用域 在python中,作用域分为两种:全局作用域和局部作用域. 全局作用域是定义在文件级别的变量,函数名.而局部作用域,则是定义函数内部. 关于作用域,我要理解两点:a.在全局不能访问到局部定 ...

  7. python 函数及变量作用域及装饰器decorator @详解

    一.函数及变量的作用   在python程序中,函数都会创建一个新的作用域,又称为命名空间,当函数遇到变量时,Python就会到该函数的命名空间来寻找变量,因为Python一切都是对象,而在命名空间中 ...

  8. python装饰器使用详解

    装饰器 '''装饰器:就是闭包(闭包的一个应用场景) -- 把要被装饰的函数作为外层函数的参数通过闭包操作后返回一个替代版函数 优点: -- 丰富了原有函数的功能 -- 提高了程序的可拓展性''' 开 ...

  9. 进阶Python:装饰器 全面详解

    进阶Python:装饰器 前言 前段时间我发了一篇讲解Python调试工具PySnooper的文章,在那篇文章开始一部分我简单的介绍了一下装饰器,文章发出之后有几位同学说"终于了解装饰器的用 ...

  10. python装饰器学习详解-函数部分

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 最近阅读<流畅的python>看见其用函数写装饰器部分写的很好,想写一些自己的读书笔记. ...

随机推荐

  1. Django App使用

    App - 基本使用 作用主要用于业务功能模块开发 创建App > python manage.py startapp app01 创建成功后默认生成以下文件 默认文件讲解: 1. models ...

  2. Nginx配置网站默认https

    Nginx配置网站默认https 一.安装Nginx yum install nginx -y 二.修改nginx.conf vim /etc/nginx/nginx.conf 配置80转443 配置 ...

  3. 【WebGL系列-01】获取WebGL上下文

    获取WebGL上下文 获取上下文 WebGL上下文是从<canvas>标签中获取到的,通过canvas对象的getContext()函数可以获取WebGLRenderingContext. ...

  4. Libvirtd networks -- 为libvirtd 中虚拟机指定ip遇到的问题

    backgroup 为libvirtd 中虚拟机指定ip,操作如下: virsh --connect qemu:///system dumpxml vm01 | grep "mac addr ...

  5. sql-lab通关

    page1-less1-22 联合查询 第一关 发现是有回显的,且传入的参数是通过'1'包裹的,所以我们的payload,如下 测试列数 ?id=1' order by 3 --+ //超过第一条语句 ...

  6. pandas:字典转dataframe的注意事项

    推荐写法 参考链接 https://blog.csdn.net/u013061183/article/details/79497254

  7. python教程 入门学习笔记 第3天 编程基础常识 代码注释 变量与常量

    编程基础常识 一.注释 1.对代码的说明与解释,它不会被编译执行,也不会显示在编译结果中 2.注释分为:单行注释和多行注释 3.用#号开始,例如:#这是我的第一个python程序 4.注释可以写在单独 ...

  8. 【技术积累】Linux中的命令行【理论篇】【五】

    arpd命令 命令介绍 arpd命令是Linux系统中的一个网络工具,用于管理和操作ARP(地址解析协议)缓存.ARP协议用于将IP地址映射到MAC地址,以便在局域网中进行通信. 命令说明 arpd命 ...

  9. 在centos7.X下安装tomcat – 东凭渭水流

    发布于 14 分钟前  1 次阅读 1.下载tomcat,并用工具将tomcat传输到linux中 mkdir /oopt/tomcat 2.解压tomcat文件 tar -zxvf apache-t ...

  10. 使用API数据接口获取商品详情数据的流程

    API数据接口是开发者获取第三方平台数据的一种方式,使用API接口可以快速地获取海量的商品详情数据,相比其他方式更加高效.实时.下面将介绍使用API数据接口获取商品详情数据的主要流程和步骤: 申请AP ...