装饰器模式(Decorator Pattern)

允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

通过采用组合、而非继承的手法,Decorator模式实现了在运行时动态地扩展对象功能的能力,而且可以
根据需要扩展多个功能。避免了单独使用继承带来的“灵活性差"和"多子类衍生问题"。

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能

缺点:多层装饰比较复杂

使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销   例如游戏装备,以及各层vip,商场的多重优惠等等

应用实例:不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体

装饰器模式主要组成部分

Component:定义一个对象接口,可以给这些对象动态地添加职责

ConcreteComponent:定义一个对象,可以给这个对象添加一些职责

Decorator:维持一个指向Component的指针,并定义一个与Component接口一致的接口

ConcreteDecorator:负责向ConcreteComponent添加功能

假如我们需要为游戏中开发一种坦克,除了各种不同型号的坦克外,我们还希望在不同场合中为其增加以下一种或多种功能;比如红外线夜视功能,比如水陆两栖功能,比如卫星定位功能等等

按类继承的作法如下:

  1. //抽象坦克
  2. public abstract class Tank
  3. {
  4. public abstract void Shot();
  5. public abstract void Run();
  6. }

各种型号:

  1. //T50型号
  2. public class T50:Tank
  3. {
  4. public override void Shot()
  5. {
  6. Console.WriteLine("T50坦克平均每秒射击5发子弹");
  7. }
  8. public override void Run()
  9. {
  10. Console.WriteLine("T50坦克平均每时运行30公里");
  11. }
  12. }
  1. //T75型号
  2. public class T75 : Tank
  3. {
  4. public override void Shot()
  5. {
  6. Console.WriteLine("T75坦克平均每秒射击10发子弹");
  7. }
  8. public override void Run()
  9. {
  10. Console.WriteLine("T75坦克平均每时运行35公里");
  11. }
  12. }
  1. //T90型号
  2. public class T90 :Tank
  3. {
  4. public override void Shot()
  5. {
  6. Console.WriteLine("T90坦克平均每秒射击10发子弹");
  7. }
  8. public override void Run()
  9. {
  10. Console.WriteLine("T90坦克平均每时运行40公里");
  11. }
  12. }

各种不同功能的组合:比如IA具有红外功能接口、IB具有水陆两栖功能接口、IC具有卫星定位功能接口。

  1. //T50坦克各种功能的组合
  2. public class T50A:T50,IA
  3. {
  4. //具有红外功能
  5. }
  6. public class T50B:T50,IB
  7. {
  8. //具有水陆两栖功能
  9. }
  10. public class T50C:T50,IC
  11. {
  12.  
  13. }
  14. public class T50AB:T50,IA,IB
  15. {}
  16. public class T50AC:T50,IA,IC
  17. {}
  18. public class T50BC:T50,IB,IC
  19. {}
  20. public class T50ABC:T50,IA,IB,IC
  21. {}
  1. //T75各种不同型号坦克各种功能的组合
  2. public class T75A:T75,IA
  3. {
  4. //具有红外功能
  5. }
  6. public class T75B:T75,IB
  7. {
  8. //具有水陆两栖功能
  9. }
  10. public class T75C:T75,IC
  11. {
  12. //具有卫星定位功能
  13. }
  14. public class T75AB:T75,IA,IB
  15. {
  16. //具有红外、水陆两栖功能
  17. }
  18. public class T75AC:T75,IA,IC
  19. {
  20. //具有红外、卫星定位功能
  21. }
  22. public class T75BC:T75,IB,IC
  23. {
  24. //具有水陆两栖、卫星定位功能
  25. }
  26. public class T75ABC:T75,IA,IB,IC
  27. {
  28. //具有红外、水陆两栖、卫星定位功能
  29. }
  1. //T90各种不同型号坦克各种功能的组合
  2. public class T90A:T90,IA
  3. {
  4. //具有红外功能
  5. }
  6. public class T90B:T90,IB
  7. {
  8. //具有水陆两栖功能
  9. }
  10. public class T90C:T90,IC
  11. {
  12. //具有卫星定位功能
  13. }
  14. public class T90AB:T90,IA,IB
  15. {
  16. //具有红外、水陆两栖功能
  17. }
  18. public class T90AC:T90,IA,IC
  19. {
  20. //具有红外、卫星定位功能
  21. }
  22. public class T90BC:T90,IB,IC
  23. {
  24. //具有水陆两栖、卫星定位功能
  25. }
  26. public class T90ABC:T90,IA,IB,IC
  27. {
  28. //具有红外、水陆两栖、卫星定位功能
  29. }

由此可见,如果用类继承实现,子类会爆炸式地增长

装饰器模式实现代码:

  1. namespace Decorator
  2. {
  3. public abstract class Tank
  4. {
  5. public abstract void Shot();
  6. public abstract void Run();
  7. }
  8. }
  1. public class T50:Tank
  2. {
  3. public override void Shot()
  4. {
  5. Console.WriteLine("T50坦克平均每秒射击5发子弹");
  6. }
  7. public override void Run()
  8. {
  9. Console.WriteLine("T50坦克平均每时运行30公里");
  10. }
  11. }
  1. public class T75 : Tank
  2. {
  3. public override void Shot()
  4. {
  5. Console.WriteLine("T75坦克平均每秒射击10发子弹");
  6. }
  7. public override void Run()
  8. {
  9. Console.WriteLine("T75坦克平均每时运行35公里");
  10. }
  11. }
  1. public class T90 :Tank
  2. {
  3. public override void Shot()
  4. {
  5. Console.WriteLine("T90坦克平均每秒射击10发子弹");
  6. }
  7. public override void Run()
  8. {
  9. Console.WriteLine("T90坦克平均每时运行40公里");
  10. }
  11. }
  1. public abstract class Decorator :Tank //Do As 接口继承 非实现继承
  2. {
  3. private Tank tank; //Has a 对象组合
  4. public Decorator(Tank tank)
  5. {
  6. this.tank = tank;
  7. }
  8. public override void Shot()
  9. {
  10. tank.Shot();
  11. }
  12. public override void Run()
  13. {
  14. tank.Run();
  15. }
  16. }
  1. public class DecoratorA :Decorator
  2. {
  3. public DecoratorA(Tank tank) : base(tank)
  4. {
  5. }
  6. public override void Shot()
  7. {
  8. //Do some extension //功能扩展 且有红外功能
  9. base.Shot();
  10. }
  11. public override void Run()
  12. {
  13.  
  14. base.Run();
  15. }
  16. }
  1. public class DecoratorB :Decorator
  2. {
  3. public DecoratorB(Tank tank) : base(tank)
  4. {
  5. }
  6. public override void Shot()
  7. {
  8. //Do some extension //功能扩展 且有水陆两栖功能
  9. base.Shot();
  10. }
  11. public override void Run()
  12. {
  13. base.Run();
  14. }
  15. }
  1. public class DecoratorC :Decorator
  2. {
  3. public DecoratorC(Tank tank) : base(tank)
  4. {
  5. }
  6. public override void Shot()
  7. {
  8. //Do some extension //功能扩展 且有卫星定位功能
  9. base.Shot();
  10. }
  11. public override void Run()
  12. {
  13.  
  14. base.Run();
  15. }
  16.  
  17. }

前端调用:

  1. static void Main(string[] args)
  2. {
  3. Tank tank = new T50();
  4. DecoratorA da = new DecoratorA(tank); //且有红外功能
  5. DecoratorB db = new DecoratorB(da); //且有红外和水陆两栖功能
  6. DecoratorC dc = new DecoratorC(db); //且有红外、水陆两栖、卫星定们三种功能
  7. dc.Shot();
  8. dc.Run();
  9. }

Decorator在.NET(Stream)中的应用:

BufferedStream和CryptoStream其实就是两个包装类,这里的Decorator模式省略了抽象装饰角色(Decorator),示例代码如下:

  1. public static void Main(string[] args)
  2. {
  3. MemoryStream ms =
  4. new MemoryStream(new byte[] { ,,,,});
  5. //扩展了缓冲的功能
  6. BufferedStream buff = new BufferedStream(ms);
  7.  
  8. //扩展了缓冲,加密的功能
  9. CryptoStream crypto = new CryptoStream(buff);
  10. }
  1. public sealed class BufferedStream : Stream
  2. {
  3. // Methods
  4. private BufferedStream();
  5. public BufferedStream(Stream stream);
  6. public BufferedStream(Stream stream, int bufferSize);
  7. // Fields
  8. private int _bufferSize;
  9. private Stream _s;
  10. }

通过反编译,可以看到BufferedStream类的代码(只列出部分),它是继承于Stream类

本文参考文档:

https://www.cnblogs.com/abcdwxc/archive/2007/09/06/884495.html

https://www.runoob.com/design-pattern/decorator-pattern.html

https://www.cnblogs.com/banluduxing/p/9152453.html

23种设计模式之装饰器模式(Decorator Pattern)的更多相关文章

  1. python 设计模式之装饰器模式 Decorator Pattern

    #写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...

  2. c#设计模式之装饰器模式(Decorator Pattern)

    引子 在面向对象语言中,我们常常会听到这样一句话:组合优于继承.那么该如何去理解这句话呢? 下面我将以游戏装备为模型用简单的代码去展示它 先创建一个装备的抽象类,然后创建刀枪2个具体的业务子类 pub ...

  3. 【UE4 设计模式】装饰器模式 Decorator Pattern

    概述 描述 动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活.是一种对象结构型模式. 套路 抽象构件(Component) 具体构 ...

  4. 实践GoF的23种设计模式:装饰者模式

    摘要:装饰者模式通过组合的方式,提供了能够动态地给对象/模块扩展新功能的能力.理论上,只要没有限制,它可以一直把功能叠加下去,具有很高的灵活性. 本文分享自华为云社区<[Go实现]实践GoF的2 ...

  5. 设计模式学习--装饰者模式(Decorator Pattern)

    概念: 装饰者模式(Decorator Pattern): 动态地将功能添加到对象,相比生成子类更灵活,更富有弹性. 解决方案: 装饰者模式的重点是对象的类型,装饰者对象必须有着相同的接口,也也就是有 ...

  6. 设计模式(三)——装饰器模式(Decorator Pattern)

    发现太过于刻意按照计划来写博客,有点不实际,刚好最近在一个网课上复习AOP的知识,讲到了装饰器模式和代理模式,顺便复习总结一下. 首先了解一下装饰器模式,从名字里面可以看出来,装饰器模式就类似于房子装 ...

  7. 用最简单的例子理解装饰器模式(Decorator Pattern)

    假设有一个公司要做产品套餐,即把不同的产品组合在一起,不同的组合对应不同的价格.最终呈现出来的效果是:把产品组合的所有元素呈现出来,并显示该组合的价格. 每个产品都有名称和价格,首先设计一个关于产品的 ...

  8. C#设计模式之装饰者模式(Decorator Pattern)

    1.概述 装饰者模式,英文名叫做Decorator Pattern.装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 2 ...

  9. php装饰器模式(decorator pattern)

    十一点了. <?php /* The decorator pattern allows behavior to be added to an individual object instance ...

随机推荐

  1. 奶牛跟蜗牛,哪种动物智商更高?——T检验帮你找到答案

    奶牛跟蜗牛,都是“牛”,那么哪种动物更“牛”,智商更高呢?此时就能用到T检验来找答案~   T 检验(独立样本 T 检验),用于分析定类数据与定量数据之间的关系情况.例如,在本研究中,我们想探究奶牛跟 ...

  2. phpcms v9.6.0任意文件上传漏洞(CVE-2018-14399)

    phpcms v9.6.0任意文件上传漏洞(CVE-2018-14399) 一.漏洞描述 PHPCMS 9.6.0版本中的libs/classes/attachment.class.php文件存在漏洞 ...

  3. 老司机也晕车--java字符串String晕车之旅

    首先声明,有晕车经历的司机请自备药物,String也可能让你怀疑人生! 第一道 开胃菜 请听题!第一道题: String hello="hello world!"; String ...

  4. Python从入门到精通之环境搭建

    本章内容: Windows系统环境搭建 Linux系统环境搭建 Mac OS系统环境搭建 一.下载python安装包 下载地址:https://www.python.org/downloads/ 二. ...

  5. B-generator 1_2019牛客暑期多校训练营(第五场)

    题意 给出\(x0,x1,a,b\), \(x_i = a\cdot x_{i-1} + b\cdot x_{i-2}\),问\(x_n取模mod\) 题解 用十进制快速幂,二进制快速幂是每到下一位就 ...

  6. HDU-2795Billboard+对宽度建立线段树

    参考:  https://blog.csdn.net/qiqi_skystar/article/details/49073309 传送门:http://acm.hdu.edu.cn/showprobl ...

  7. html/css中float浮动的用法

    一.float基础用法示例 1.我们先建两个div盒子,设置高度.宽度和背景颜色: 最开始两个盒子在网页上的位置如下: 然后我们将红色盒子浮动到右边 然后我们会发现红色盒子浮动到了右边,但是蓝色盒子就 ...

  8. SpringBoot初体验之整合SpringMVC

    作为开发人员,大家都知道,SpringBoot是基于Spring4.0设计的,不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程.另外Spr ...

  9. LVM(逻辑卷管理)

    一.LVM概念 LVM是逻辑盘卷管理(Logical Volume Manager)的简称,它是Linux环境下对磁盘分区进行管理的一种机制,LVM是建立在硬盘和分区之上的一个逻辑层,来提高磁盘分区管 ...

  10. mybatis源码专题(2)--------一起来看下使用mybatis框架的insert语句的源码执行流程吧

    本文是作者原创,版权归作者所有.若要转载,请注明出处.本文以简单的insert语句为例 1.mybatis的底层是jdbc操作,我们先来回顾一下insert语句的执行流程,如下 执行完后,我们看下数据 ...