基础介绍:

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

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

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

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

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

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

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

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

  大家思考一个问题,如果有很多个装饰并且想随意组合的话,那就有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. 《最新出炉》系列入门篇-Python+Playwright自动化测试-7-浏览器的相关操作

    1.简介 上一篇已经将playwright的元素定位大法基本介绍的差不多了,但是在Web的UI自动化的测试中,我们通常需要使用一些方法来操作浏览器,今天就跟随学习了解一下.这一篇宏哥主要是介绍一下,在 ...

  2. Flutter系列文章-Flutter基础

    Flutter是Google推出的一种新的移动应用开发框架,允许开发者使用一套代码库同时开发Android和iOS应用.它的设计理念.框架结构.以及对Widget的使用,都让开发者能更有效率地创建高质 ...

  3. vue+element 判断table表格输入不能为空

    点击确定的时候,判断表格其中某行某值不能为空 1.HTML <div class="app-container"> <el-form ref="form ...

  4. Vortex Indicator 构建交易策略

    更多精彩内容,欢迎关注公众号:数量技术宅,也可添加技术宅个人微信号:sljsz01,与我交流. 今天的文章,我们将为大家介绍一个与DMI(Directional Movement Index)类似,判 ...

  5. 磁盘问题和解决: fsck,gdisk,fdisk等

    错误: Resize inode not valid 对于gpt分区的硬盘一般fsck只能检查分区, 不能用于检查整个硬盘, 但是如果对硬盘设备运行时遇到这样的错误 $ sudo fsck -n /d ...

  6. [nginx]日志中记录自定义请求头

    前言 假设在请求中自定义了一个请求头,key为"version",参数值为"1.2.3",需要在日志中捕获这个请求头. nginx日志配置 只需要用变量http ...

  7. 【go笔记】TCP编程

    前言 TCP服务端的处理流程 监听端口 接收客户端请求建立连接 创建goroutine处理链接 示例代码:TCP服务端 package main import ( "net" &q ...

  8. 《CUDA编程:基础与实践》读书笔记(2):CUDA内存

    1. 全局内存 核函数中的所有线程都能够访问全局内存(global memory).全局内存的容量是所有设备内存中最大的,但由于它没有放在GPU芯片内部,因此具有相对较高的延迟和较低的访问速度,cud ...

  9. Python实现商城购物经典案例

    代码分步骤思路: 商城添加商品:opea_db = [{'store_name': '手机','num': 1}] while True: store_name=input('请输入需要存放的商品(按 ...

  10. [ABC150E] Change a Little Bit

    2023-03-10 题目 题目传送门 翻译 翻译 难度&重要性(1~10):7 题目来源 AtCoder 题目算法 数学,贪心 解题思路 显然 \(C_i\) 越小的位越早被修改越好.所以我 ...