※设计模式※→☆结构型模式☆============Decorator模式(九)

模式概述

在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任。典型模式代表: DecoratorBridge

Bridge的核心就是将抽象和实现分离, 让二者独立变化当需要将类的行为和属性分离的时候,可以采用Bridge模式, 在抽象体实现属性, 在实现体实现行为, 从而达到属性和行为能独立变化, 他们之间通过桥接(也就是将二者绑定, 在抽象类中隐藏)的方式来进行关联, 而且这种桥接绑定的关系是可动态改变的, 这也是与继承相比最大的优点, 有时候我们也可以将其理解为代理模式的一种演化, 将行为代理给各个不同的行为实现类来处理。

※设计模式※→☆结构型模式☆============Bridge模式(七)

上述Bridge模式中,电脑类型(抽象)与电脑厂商(实体)通过桥接(也就是将二者绑定, 在抽象类中隐藏)的方式处理, 从而达到属性和行为能独立变化。

例如卖咖啡的经典例子:一杯咖啡为例,有中杯和大杯之分,同时还有加奶 不加奶之分. 如果用单纯的继承,这四个具体实现(中杯 大杯 加奶 不加奶)之间有概念重叠,因为有中杯加奶,也有中杯不加奶, 如果再在中杯这一层再实现两个继承,很显然混乱,扩展性极差.那我们也使用Bridge模式来实现它. 中杯/大杯(抽象)与加奶/不加奶(实体)。

        Decorator模式适用于子类的继承层次过深的情况,可以很巧妙的减少继承层数,并有效的的减少实现功能所需的代码量,无疑又是OO思想的一把利器。当需要对一个类增加新操作时,我们习惯的做法是将此类作为父类,然后再继承一个子类,将需要的实现放到子类中。但这样会带来一个问题,当我们需要的功能随着项目的进展而逐渐增多时,我们不得不每增加几项项操作,就继承一个子类,到了一定程度时,我们发现继承层数将会是空前的深,而且抽象基类为了实现多态, 必须为每一项操作新增一个纯虚函数。对于类似种种问题,Decorator模式给出了很好的解决方案,在抽象基类中,我们将看到虚函数是何等的少。

Decorator模式动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。不改变接口的前提下,增强所考虑的类的性能。

  •     1)需要扩展一个类的功能,或给一个类增加附加责任。
  •     2)需要动态的给一个对象增加功能,这些功能可以再动态地撤销。
  •     3)需要增加一些基本功能的排列组合而产生的非常大量的功能,从而使继承变得    不现实。

Decorator模式由以下角色组成

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

模式结构

模式讨论

Decorator模式应用在某些情况下我们可能会“过度地使用继承来扩展对象的功能”,由于基础为类型引入的静态特指,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各个子类的组合(扩展功能的组合)会导致各种子类的膨胀。

  • 在某些情况下我们可能会“过度的使用继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多的子类膨胀。即我们需要找到一种方式,实现功能可通过非继承方式扩展,但是接口不发生变化的类。
  • 如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能
    扩展变化”所导致的影响将为最低。

根据上述内容,我们可以发现Decorator模式有以下要点

  • 1.通过采用组合并非继承的手法,Decorator模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的”灵活性差“和”多子类衍生问题“
  • 2.Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。
  • 3.Decorator模式的目的并非解决”多字类衍生的多继承“问题,Decorator模式应用的要点在于解决”主体类在多个方向上的扩展功能“(显然file,network与加密,缓冲是两种扩展方向) ——是为”装饰“的含义。

Decorator和Bridge的区别

Decorator是对已有功能的增强, 装饰类都是围绕被装饰类已有的功能而展开的, 无论装饰类怎么变, 它都必须围绕被装饰类来变化(或者是围绕二者公共的接口来变化), 因为对于客户程序来说, 调用装饰前后的对象应该是一致的.

Bridge模式是将行为从被桥接对象(抽象类)中分离出去, 完全放到实现类中去实现, 行为实现将更少的受到被桥接对象的限制. 所以如果这种约束是必要的,就可以采用Decorator模式, 反之则可以采用Bridge模式

 

Decorator,Bridge,Adapter的区别

  • Adapter:将两个不兼容的类纠合在一起使用 (项目开发后期兼容)
  • Bridge:将抽象和行为划分开来,各自独立,但能动态的结合 (项目开发初期设计)
  • Decorator:动态给一个对象添加一些额外的职责 (项目开发后期维护)

为了加强理解,我仍然使用了电脑[构件](桌面,笔记本,服务器),厂商[角色](ASUS,DELL,HP)的例子来处理。无论是电脑类型的变化,还是厂商的变化。一旦随需求的变化,子类急剧膨胀,同时充斥着重复代码,关键是划清责任。

Bridge: 通过电脑类型(抽象)与电脑厂商(实体)的方式进行组合,3抽象类*3实体类可表述9种类型的电脑组合。但无法将电脑厂商(实体)进行混合,例如:某电脑既有ASUS功能,又有HP功能。

Decorator: 通过电脑类型(构件)与电脑厂商(角色)的方式进行添加职责,3构件+XX角色类可表述多种类型的电脑组合。桌面电脑+ASUS功能,桌面电脑+ASUS功能+DELL功能等。相比Bridge来说更加灵活。

可以从UML图中看出来,若右边实现受到左边对象的限制约束必要的,就可以采用Decorator模式, 反之则可以采用Bridge模式

 

最后,无论模式多么优越,我们也需要根据实际的具体情况而慎重考虑。

 

模式实现

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
以后的笔记潇汀会尽量详细讲解一些相关知识的,希望大家继续关注我的博客。
本节笔记到这里就结束了。

潇汀一有时间就会把自己的学习心得,觉得比较好的知识点写出来和大家一起分享。
编程开发的路很长很长,非常希望能和大家一起交流,共同学习,共同进步。
如果文章中有什么疏漏的地方,也请大家指正。也希望大家可以多留言来和我探讨编程相关的问题。
最后,谢谢你们一直的支持~~~

       C++完整个代码示例(代码在VS2017下测试可运行)
代码及相关资料下载地址:
              https://gitee.com/arvinxt/DesignPattern

发布了170 篇原创文章 · 获赞 207 · 访问量 459万+

猜你喜欢

转载自blog.csdn.net/xiaoting451292510/article/details/103569917