一、引言

在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类)、AccessoriesPhone(挂件手机类)等,这样就会导致 ”子类爆炸“问题,为了解决这个问题,我们可以使用装饰者模式来动态地给一个对象添加额外的职责。下面让我们看看装饰者模式。

二、装饰者模式的详细介绍

2.1 定义

装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相比生成子类可以更灵活地增加功能。

2.2 装饰者模式实现

这里以手机和手机配件的例子来演示装饰者模式的实现,具体代码如下:

/// <summary>/// 手机抽象类,即装饰者模式中的抽象组件类/// </summary>public abstract class Phone{public abstract void Print();}/// <summary>/// 苹果手机,即装饰着模式中的具体组件类/// </summary>public class ApplePhone:Phone{/// <summary>/// 重写基类方法/// </summary>public override void Print(){Console.WriteLine("开始执行具体的对象——苹果手机");}}/// <summary>/// 装饰抽象类,要让装饰完全取代抽象组件,所以必须继承自Photo/// </summary>public abstract class Decorator:Phone{private Phone phone;public Decorator(Phone p){this.phone = p;}public override void Print(){if (phone != null){phone.Print();}}}/// <summary>/// 贴膜,即具体装饰者/// </summary>public class Sticker : Decorator{public Sticker(Phone p): base(p){ }public override void Print(){base.Print();// 添加新的行为
            AddSticker();      }/// <summary>/// 新的行为方法/// </summary>public void AddSticker(){Console.WriteLine("现在苹果手机有贴膜了");}}/// <summary>/// 手机挂件/// </summary>public class Accessories : Decorator{public Accessories(Phone p): base(p){}public override void Print(){base.Print();// 添加新的行为
            AddAccessories();          }/// <summary>/// 新的行为方法/// </summary>public void AddAccessories(){Console.WriteLine("现在苹果手机有漂亮的挂件了");}}

此时客户端调用代码如下:

class Customer{static void Main(string[] args){// 我买了个苹果手机Phone phone = new ApplePhone();// 现在想贴膜了Decorator applePhoneWithSticker = new Sticker(phone);// 扩展贴膜行为
            applePhoneWithSticker.Print();Console.WriteLine("----------------------\n");// 现在我想有挂件了Decorator applePhoneWithAccessories = new Accessories(phone);// 扩展手机挂件行为
            applePhoneWithAccessories.Print();Console.WriteLine("----------------------\n");// 现在我同时有贴膜和手机挂件了Sticker sticker = new Sticker(phone);Accessories applePhoneWithAccessoriesAndSticker = new Accessories(sticker);applePhoneWithAccessoriesAndSticker.Print();Console.ReadLine();}

从上面的客户端代码可以看出,客户端可以动态地将手机配件增加到手机上,如果需要添加手机外壳时,此时只需要添加一个继承Decorator的手机外壳类,从而,装饰者模式扩展性也非常好。

2.3 装饰者模式的类图

实现完了装饰者模式之后,让我们看看装饰者模式实现中类之间的关系,具体见下图:

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

  • 抽象构件(Phone)角色:给出一个抽象接口,以规范准备接受附加责任的对象。
  • 具体构件(AppPhone)角色:定义一个将要接收附加责任的类。
  • 装饰(Dicorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
  • 具体装饰(Sticker和Accessories)角色:负责给构件对象 ”贴上“附加的责任。

三、装饰者模式的优缺点

看完装饰者模式的详细介绍之后,我们继续分析下它的优缺点。

优点:

  1. 装饰这模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活
  2. 通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合
  3. 装饰者模式有很好地可扩展性

缺点:装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变的更复杂。并且更多的对象会是的差错变得困难,特别是这些对象看上去都很像。

四、使用场景

下面让我们看看装饰者模式具体在哪些情况下使用,在以下情况下应当使用装饰者模式:

  1. 需要扩展一个类的功能或给一个类增加附加责任。
  2. 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能

五、.NET中装饰者模式的实现

在.NET 类库中也有装饰者模式的实现,该类就是System.IO.Stream,下面看看Stream类结构:

上图中,BufferedStream、CryptoStream和GZipStream其实就是两个具体装饰类,这里的装饰者模式省略了抽象装饰角色(Decorator)。下面演示下客户端如何动态地为MemoryStream动态增加功能的。

 MemoryStream memoryStream = new MemoryStream(new byte[] {95,96,97,98,99});// 扩展缓冲的功能BufferedStream buffStream = new BufferedStream(memoryStream);// 添加加密的功能CryptoStream cryptoStream = new CryptoStream(memoryStream,new AesManaged().CreateEncryptor(),CryptoStreamMode.Write);// 添加压缩功能GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Compress, true);

六、总结

到这里,装饰者模式的介绍就结束了,装饰者模式采用对象组合而非继承的方式实现了再运行时动态地扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了单独使用继承带来的 ”灵活性差“和”多子类衍生问题“。同时它很好地符合面向对象设计原则中 ”优先使用对象组合而非继承“和”开放-封闭“原则。

本专题所有源码:设计模式之装饰者模式

C#设计模式(9)——装饰者模式(Decorator Pattern)相关推荐

  1. python中的装饰器、装饰器模式_python 设计模式之装饰器模式 Decorator Pattern

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

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

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

  3. 锈才学设计模式之 —— 装饰者模式(Decorate Pattern)

    锈才学设计模式之  -- 装饰者模式 装饰者模式:在运行时动态的将行为扩展到装饰者对象上,符合"对扩展开放,对修改关闭"原则. 说明: 通俗点说,装饰者模式就是,一个类把另一个类装 ...

  4. 设计模式(三):“花瓶+鲜花”中的装饰者模式(Decorator Pattern)

    在前两篇博客中详细的介绍了"策略模式"和"观察者模式",今天我们就通过花瓶与鲜花的例子来类比一下"装饰模式"(Decorator Patte ...

  5. 极速理解设计模式系列:23.装饰器模式(Decorator Pattern)

    五个角色:部件(Component).具体部件(ConcreteComponent).装饰抽象类(Decorator).具体装饰对象(ConcreteDecorator).客户端(Client) 部件 ...

  6. 设计模式 -结构型模式_ 装饰者模式Decorator Pattern 在开源软件中的应用

    文章目录 定义 结构图 需求 装饰者模式 装饰者模式在MyBatis中的应用 小结 定义 装饰模式 Decorator : 在不改变原有功能的基础上, 动态的给一个对象添加一些额外的职责 ,非常符合开 ...

  7. 【Java设计模式系列】装饰器模式(Decorator Pattern)

    简介 一般有两种方式可以给一个类或对象新增行为: 继承 子类在拥有自身方法同时还拥有父类方法.但这种是静态的,用户无法控制增加行为的方式和时机. 关联 将一个类的对象嵌入另一个对象,由另一个对象决定是 ...

  8. C++实现装饰者模式Decorator Pattern

    设计原则5:类应该对扩展开放,对修改关闭. 目标:允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为. 好处:设计具有弹性可以应对改变,可以接受新的功能来应对改变的需求. 遇到的问题:类数量爆 ...

  9. 设计模式之装饰者模式Decorator

    装饰者模式,动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更加有弹性的替代方案 结构说明 1.Component抽象组件,是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对 ...

  10. 装饰者模式(Decorator pattern)

    说起来惭愧,在某群解答别人问题时居然回答错误,羞煞我也.为此特地补习一下. :( 装饰者模式 作用: 动态给对象添加职责 典型案例: 在一般的留言本中(支持UBB)输入文本,按B设置为粗体,I为斜体, ...

最新文章

  1. laravel mysql 锁表_Laravel 数据库加密及数据库表前缀配置方法
  2. npm获取配置,设置代理
  3. python的moviepy库 打包 报错: ‘moviepy.audio.fx.all‘ has no attribute ‘audio_fade 的解决办法
  4. 为什么要搭建自己的缓存管理模块?
  5. 【IDEA】idea es 报错 Cause: invalid type code: 2D
  6. api返回的数据结构_JavaScript中的数据结构数组 和 栈
  7. 3.1.1 Spring 简介
  8. 制定Windows重要安全计划——12步纲要
  9. 计算机软件版本号是什么意思,带你深入了解解密Windows系统版本和版本号
  10. Ubuntu 解决WPS缺少宋体,微软雅黑等中文字体
  11. 大脑神经网络记忆原理图,记忆力机制的神经网络
  12. 谷歌高级软件工程师的一天
  13. Moses的安装、训练和优化
  14. 判断自定义异形view的点击事件是否在绘制区域内
  15. [前端基础] JavaScript 进阶篇
  16. JavaScript(WebAPI)
  17. c#笔试基础(转载)
  18. Java中Stream的close
  19. 群晖系统怎么进入本地服务器,群晖云服务器如何使用本地打印机
  20. UPS原理与并机冗余方案

热门文章

  1. 《MySQL——基于位点orGTID的主备切换协议》
  2. 操作系统大内核和微内核_操作系统中的内核
  3. readdir函数_PHP readdir()函数与示例
  4. 黑色背景下,将照片内封闭空心图案的空心区域染成Cyan并保存
  5. ffmpeg 使用ffplay 进行 hls 拉流 分析 1
  6. 栈应用_计算按运算符优先级分布的算式(代码、分析、汇编)
  7. c语言1e3和1e3,自考“高级语言程序设计”习题答案详解(33)
  8. mysql主从1594错误_3分钟解决MySQL主从1594错误
  9. linux双网卡端口聚合,Linux双网卡聚合改造
  10. 计算机网路【2】数据链路层