4.4-Decorator「wrapper」-装饰器-结构型模式

目的

动态地向对象添加额外功能,比创建子类更加灵活

示例

GUI 工具箱允许你对任意一个用户界面组件添加一些特性(例如边框),或是一些行为(例如窗口滚动)。

一种较为灵活的方式是将组件嵌入另一个对象中,由这个对象添加边框。我们称这个嵌入的对象为装饰

  • 这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明(因此可以递归地嵌套)
  • 它将客户请求转发给该组件,并且可能在转发前后执行一些额外的动作(例如画一个边框)。 600

适用性

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 处理那些可以撤销的职责。
  • 当不能采用生成子类的方法进行扩充时,例如:
    • 可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长
    • 类定义被隐藏或类是 final 的

结构

  • Component:对象接口
  • ConcreteComponent
  • Decorator:维护指向 Component 的指针,定义和 Component 一致的接口
  • ConcreteDecorator:向组件添加职责(将操作代理给所持有的对象,并附加自身的操作)

优缺点

  • 比静态继承更灵活:
    • 可以用添加和分离装饰器的方法,用装饰在运行时增加和删除职责
    • 可以很容易地重复添加一个特性
  • 避免在层次结构高层的类有太多的特征
  • Decorator 相比 Component 模式而言,是完全透明的包装,使用装饰时不应当依赖对象标识

缺点:有许多小对象:采用 Decorator 模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在它们相互连接的方式上有所不同,而不是它们的类或是它们的属性值有所不同。尽管对于那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难

实现

  • 接口一致性:装饰器必须和被装饰的对象接口一致
  • 省略抽象的装饰器:仅需要添加一个职责时,没有必要定义抽象 Decorator 类
  • 保持 Component 类的简单性:为保证一致性,组件和装饰器必须有共同的 Component 父类,因此需要避免这个类过大。这个父类应集中于定义接口而不是存储数据,对数据表示的定义应延迟到子类中

相关模式

  • Adapter(4.1):Decorator 模式不同于 Adapter 模式,因为装饰仅改变对象的职责而不改变它的接口;而适配器将给对象一个全新的接口。
  • Composite(4.3):可以将装饰视为一个退化的、仅有一个组件的组合。然而,装饰仅给对象添加一些额外的职责——它的目的不在于对象聚集。

装饰器 VS 策略模式

改变对象的行为主要有两种方式:

  • Decorator 模式改变外壳
  • Strategy 模式改变内核

当 Component 类原本就很庞大时,使用 Decorator 模式代价太高, Strategy 模式相对好一些