热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C#设计模式之八装饰模式(DecoratorPattern)【结构型】

一、引言今天我们要讲【结构型】设计模式的第三个模式,该模式是【装饰模式】,英文名称:DecoratorPattern。我第一次看到这个名称想到的是另外一个词语“装修”,我就说说我对“装修”的理

一、引言

   今天我们要讲【结构型】设计模式的第三个模式,该模式是【装饰模式】,英文名称:Decorator Pattern。我第一次看到这个名称想到的是另外一个词语“装修”,我就说说我对“装修”的理解吧,大家一定要看清楚,是“装修”,不是“装饰”。我们长大了,就要结婚,要结婚就涉及到要买房子,买的精装修或者简单装修就可以住的,暂时不谈。我们就谈谈我们购买的是毛坯房。如果我想要房子的内饰是大理石风格的,我们只要在毛坯房的基础之上用大理石风格的材料装修就可以,我们当然不可能为了要一个装修风格,就把刚刚盖好的房子拆了在重新来过。房子装修好了,我们就住了进来,很开心。过了段时间,我们发现我们的房子在冬季比较冷,于是我就想给我们的房子增加保暖的功能,装修好的房子我们可以继续居住,我们只是在房子外面加一层保护层就可以了。又过了一段时间,总是有陌生人光顾,所以我们想让房子更安全,于是我们在外墙和房顶加装安全摄像头,同时门窗也增加安全系统。随着时间的流逝,我们可能会根据我们的需求增加相应的功能,期间,我们的房子可以正常使用,加上什么设施就有了相应的功能。从这一方面来讲,“装修”和“装饰”有类似的概念,接下来就让我们看看装饰模式具体是什么吧!

二、装饰模式的详细介绍

2.1、动机(Motivate)

   在房子装修的过程中,各种功能可以相互组合,来增加房子的功用。类似的,如果我们在软件系统中,要给某个类型或者对象增加功能,如果使用“继承”的方案来写代码,就会出现子类暴涨的情况。比如:IMarbleStyle是大理石风格的一个功能,IKeepWarm是保温的一个接口定义,IHouseSecurity是房子安全的一个接口,就三个接口来说,House是我们房子,我们的房子要什么功能就实现什么接口,如果房子要的是复合功能,接口不同的组合就有不同的结果,这样就导致我们子类膨胀严重,如果需要在增加功能,子类会成指数增长。这个问题的根源在于我们“过度地使用了继承来扩展对象的功能”,由于继承为类型引入的静态特质(所谓静态特质,就是说如果想要某种功能,我们必须在编译的时候就要定义这个类,这也是强类型语言的特点。静态,就是指在编译的时候要确定的东西;动态,是指运行时确定的东西),使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀(多继承)。如何使“对象功能的扩展”能够根据需要来动态(即运行时)地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响降为最低?

2.2、意图(Intent)

   动态地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类更为灵活。         ——  《设计模式》GoF

2.3、结构图(Structure)

      

2.4、模式的组成

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

  (1)、抽象构件角色(Component):给出一个抽象接口,以规范准备接收附加责任的对象。

  (2)、具体构件角色(Concrete Component):定义一个将要接收附加责任的类。

  (3)、装饰角色(Decorator):持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口。

  (4)、具体装饰角色(Concrete Decorator):负责给构件对象添加上附加的责任。

2.5 、装饰模式的具体代码实现

   刚开始一看这个“装饰模式”是有点不太好理解,既然这个模式是面向对象的设计模式,那在现实生活中一定有事例和其对应,其实这种例子也不少,大家好好的挖掘吧,也可以提高我们对面向对象的理解。我继续拿盖房子来说事吧。
 

 1 namespace 装饰模式的实现
 2 {
 3     /// 
 4     /// 该抽象类就是房子抽象接口的定义,该类型就相当于是Component类型,是饺子馅,需要装饰的,需要包装的
 5     /// 
 6     public abstract class House
 7     {
 8         //房子的装修方法--该操作相当于Component类型的Operation方法
 9         public abstract void Renovation();
10     }
11 
12     /// 
13     /// 该抽象类就是装饰接口的定义,该类型就相当于是Decorator类型,如果需要具体的功能,可以子类化该类型
14     /// 
15     public abstract class DecorationStrategy:House //关键点之二,体现关系为Is-a,有这这个关系,装饰的类也可以继续装饰了
16     {
17        //通过组合方式引用Decorator类型,该类型实施具体功能的增加
18         //这是关键点之一,包含关系,体现为Has-a
19         protected House _house;
20 
21         //通过构造器注入,初始化平台实现
22         protected DecorationStrategy(House house)
23         {
24            this._house=house;
25         }
26 
27        //该方法就相当于Decorator类型的Operation方法
28        public override void Renovation()
29        {
30            if(this._house!=null)
31             {
32                 this._house.Renovation();
33             }
34         }
35     }
36  
37     /// 
38     /// PatrickLiu的房子,我要按我的要求做房子,相当于ConcreteComponent类型,这就是我们具体的饺子馅,我个人比较喜欢韭菜馅
39     /// 
40     public sealed class PatrickLiuHouse:House
41     {
42         public override void Renovation()
43         {
44             Console.WriteLine("装修PatrickLiu的房子");
45         }
46     }
47  
48 
49    /// 
50     /// 具有安全功能的设备,可以提供监视和报警功能,相当于ConcreteDecoratorA类型
51     /// 
52     public sealed class HouseSecurityDecorator:DecorationStrategy
53     {
54         public  HouseSecurityDecorator(House house):base(house){}
55 
56         public override void Renovation()
57         {
58             base.Renovation();
59             Console.WriteLine("增加安全系统");
60         }
61     }
62  
63     /// 
64     /// 具有保温接口的材料,提供保温功能,相当于ConcreteDecoratorB类型
65     /// 
66     public sealed class KeepWarmDecorator:DecorationStrategy
67     {
68         public  KeepWarmDecorator(House house):base(house){}
69 
70         public override void Renovation()
71         {
72             base.Renovation();
73             Console.WriteLine("增加保温的功能");
74         }
75     }
76 
77    public class Program
78    {
79       static void Main()
80       {
81          //这就是我们的饺子馅,需要装饰的房子
82          House myselfHouse=new PatrickLiuHouse();
83 
84          DecorationStrategy securityHouse=new HouseSecurityDecorator(myselfHouse);
85          securityHouse.Renovation();
86          //房子就有了安全系统了
87 
88          //如果我既要安全系统又要保暖呢,继续装饰就行
89          DecorationStrategy securityAndWarmHouse=new HouseSecurityDecorator(securityHouse);
90          securityAndWarmHouse.Renovation();
91       }
92    }
93 }


    写了很多备注,大家好好体会一下,里面有两个关键点,仔细把握。

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

    2、Component类在Decorator模式中充当抽象接口的角色,不应该去实现具体的行为。而且Decorator类对于Component类应该透明——换言之Component类无需知道Decorator类,Decorator类是从外部来扩展Component类的功能。

    3、Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。我们可以使用一个或者多个Decorator对象来“装饰”一个Component对象,且装饰后的对象仍然是一个Component对象。

    4、Decorator模式并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。

     3.1】、装饰模式的优点:

             (1)、把抽象接口与其实现解耦。

             (2)、抽象和实现可以独立扩展,不会影响到对方。

             (3)、实现细节对客户透明,对用于隐藏了具体实现细节。

      3.2】、装饰模式的缺点:

           (1)、增加了系统的复杂度

      3.3】、在以下情况下应当使用桥接模式:

          (1)、如果一个系统需要在构件的抽象化角色和具体化角色之间添加更多的灵活性,避免在两个层次之间建立静态的联系。

          (2)、设计要求实现化角色的任何改变不应当影响客户端,或者实现化角色的改变对客户端是完全透明的。

          (3)、需要跨越多个平台的图形和窗口系统上。

          (4)、一个类存在两个独立变化的维度,且两个维度都需要进行扩展。

四、.NET 中装饰模式的实现

    在Net框架中,有一个类型很明显的使用了“装饰模式”,这个类型就是Stream。Stream类型是一个抽象接口,它在System.IO命名空间里面,它其实就是Component。FileStream、NetworkStream、MemoryStream都是实体类ConcreteComponent。右边的BufferedStream、CryptoStream是装饰对象,它们都是继承了Stream接口的。

   如图:
      

    Stream就相当于Component,定义装饰的对象,FileStream就是要装饰的对象,BufferedStream是装饰对象。我们看看BufferedStream的定义,部分定义了。

1 public sealed class BufferedStream : Stream
2 {
3     private const int _DefaultBufferSize = 4096;
4 
5     private Stream _stream;

 结构很简单,对比结构图看吧,没什么可说的了。

五、总结

     今天的文章就写到这里了,总结一下我对这个模式的看法,这个模式有点像包饺子,ConcreteComponent其实是饺子馅,Decorator就像饺子皮一样,包什么皮就有什么的样子,皮和皮也可以嵌套,当然我们生活中的饺子只是包一层。其实手机也是一个装饰模式使用的好例子,以前我们的手机只是接打电话,然后可以发短信和彩信,我在装饰一个就可以拍照了。我们现在的手机功能很丰富,其结果也类似装饰的结果。随着社会的进步,技术发展,模块化的手机也出现了,其设计原理也和“装饰模式”就更接近了。不光手机,还有我们身边其他很多家用电器也有类似的发展经历,我们努力发现生活中的真理吧,然后再在软件环境中慢慢体会吧。


推荐阅读
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
  • 本题探讨如何通过最大流算法解决农场排水系统的设计问题。题目要求计算从水源点到汇合点的最大水流速率,使用经典的EK(Edmonds-Karp)和Dinic算法进行求解。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • 360SRC安全应急响应:从漏洞提交到修复的全过程
    本文详细介绍了360SRC平台处理一起关键安全事件的过程,涵盖从漏洞提交、验证、排查到最终修复的各个环节。通过这一案例,展示了360在安全应急响应方面的专业能力和严谨态度。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
  • 本文探讨了《魔兽世界》中红蓝两方阵营在备战阶段的策略与实现方法,通过代码展示了双方如何根据资源和兵种特性进行战士生产。 ... [详细]
  • 最近团队在部署DLP,作为一个技术人员对于黑盒看不到的地方还是充满了好奇心。多次咨询乙方人员DLP的算法原理是什么,他们都以商业秘密为由避而不谈,不得已只能自己查资料学习,于是有了下面的浅见。身为甲方,虽然不需要开发DLP产品,但是也有必要弄明白DLP基本的原理。俗话说工欲善其事必先利其器,只有在懂这个工具的原理之后才能更加灵活地使用这个工具,即使出现意外情况也能快速排错,越接近底层,越接近真相。根据DLP的实际用途,本文将DLP检测分为2部分,泄露关键字检测和近似重复文档检测。 ... [详细]
  • 毕业设计:基于机器学习与深度学习的垃圾邮件(短信)分类算法实现
    本文详细介绍了如何使用机器学习和深度学习技术对垃圾邮件和短信进行分类。内容涵盖从数据集介绍、预处理、特征提取到模型训练与评估的完整流程,并提供了具体的代码示例和实验结果。 ... [详细]
  • 利用决策树预测NBA比赛胜负的Python数据挖掘实践
    本文通过使用2013-14赛季NBA赛程与结果数据集以及2013年NBA排名数据,结合《Python数据挖掘入门与实践》一书中的方法,展示如何应用决策树算法进行比赛胜负预测。我们将详细讲解数据预处理、特征工程及模型评估等关键步骤。 ... [详细]
  • Docker的安全基准
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Valve 发布 Steam Deck 的新版 Windows 驱动程序
    Valve 最新发布了针对 Steam Deck 掌机的 Windows 驱动程序,旨在提升其在 Windows 环境下的兼容性、安全性和性能表现。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 在进行QT交叉编译时,可能会遇到与目标架构不匹配的宏定义问题。例如,当为ARM或MIPS架构编译时,需要确保使用正确的宏(如QT_ARCH_ARM或QT_ARCH_MIPS),而不是默认的QT_ARCH_I386。本文将详细介绍如何正确配置编译环境以避免此类错误。 ... [详细]
author-avatar
暖暖252
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有