1. 人人编程首页
  2. 架构设计

装饰器设计模式

意图

  • 动态地将附加职责附加到对象。装饰器为扩展功能提供了一种灵活的替代子类的方法。
  • 通过递归包装核心对象的客户指定修饰。
  • 包装礼物,将其放入盒子中,然后将盒子包裹起来。

问题

您想在运行时向单个对象添加行为或状态。继承是不可行的,因为它是静态的并且适用于整个类。

讨论

假设您正在开发一个用户界面工具包,并且您希望支持向窗口添加边框和滚动条。您可以定义一个继承层次结构,如…

装饰器设计模式

但是装饰器模式建议让客户能够指定所需的任何“功能”组合。

Widget* aWidget = new BorderDecorator(
  new HorizontalScrollBarDecorator(
    new VerticalScrollBarDecorator(
      new Window( 80, 24 ))));
aWidget->draw();

这种灵活性可以通过以下设计来实现

装饰器设计模式

将功能级联(或链接)在一起以生成自定义对象的另一个示例可能看起来像…

Stream* aStream = new CompressingStream(
  new ASCII7Stream(
    new FileStream("fileName.dat")));
aStream->putString( "Hello world" );

此类问题的解决方案涉及将原始对象封装在抽象包装器接口中。装饰器对象和核心对象都继承自这个抽象接口。该接口使用递归组合来允许将无限数量的装饰器“层”添加到每个核心对象。

请注意,此模式允许向对象添加职责,而不是向对象接口添加方法。由于指定了连续的层,呈现给客户端的接口必须保持不变。

另请注意,核心对象的身份现在已“隐藏”在装饰器对象中。尝试直接访问核心对象现在是一个问题。

结构

客户总是对CoreFunctionality.doThis()OptionalOne.doThis() 客户可能对和可能不感兴趣OptionalTwo.doThis()。这些类中的每一个总是委托给 Decorator 基类,并且该类总是委托给包含的“wrappee”对象。

装饰器设计模式

例子

装饰器动态地为对象附加额外的职责。添加到松树或枞树上的装饰品是装饰者的例子。灯饰、花环、糖果手杖、玻璃饰品等,可以添加到树上,让它看起来充满节日气氛。无论使用何种特定装饰品,这些装饰品都不会改变可识别为圣诞树的树本身。作为附加功能的一个示例,添加灯可以“点亮”一棵圣诞树。

另一个例子:突击枪本身就是一种致​​命的武器。但是你可以应用某些“装饰”来使它更准确、更安静和更具破坏性。

装饰器设计模式

检查清单

  1. 确保上下文是:单个核心(或非可选)组件、几个可选的装饰或包装器以及对所有人通用的接口。
  2. 创建一个“最小公分母”接口,使所有类都可以互换。
  3. 创建第二级基类(装饰器)以支持可选的包装类。
  4. Core 类和 Decorator 类继承自 LCD 接口。
  5. Decorator 类声明了与 LCD 接口的组合关系,该数据成员在其构造函数中初始化。
  6. Decorator 类委托给 LCD 对象。
  7. 为每个可选的装饰定义一个 Decorator 派生类。
  8. 装饰器派生类实现它们的包装器功能 – 并且 – 委托给装饰器基类。
  9. 客户端配置 Core 和 Decorator 对象的类型和顺序。

经验法则

  • 适配器为其主题提供了不同的接口。代理提供相同的接口。装饰器提供了一个增强的接口。
  • Adapter 改变了对象的接口,Decorator 增强了对象的职责。因此,装饰器对客户端更加透明。因此,装饰器支持递归组合,这在纯适配器中是不可能的。
  • Composite 和 Decorator 具有相似的结构图,反映了两者都依赖递归组合来组织无限数量的对象的事实。
  • 装饰器可以被视为只有一个组件的退化组合。然而,装饰者增加了额外的责任——它不是为对象聚合而设计的。
  • 装饰器旨在让您无需子类化就可以向对象添加职责。Composite的重点不是装饰,而是表现。这些意图是不同但互补的。因此,Composite 和 Decorator 经常一起使用。
  • Composite 可以使用责任链让组件通过其父级访问全局属性。它还可以使用装饰器来覆盖部分合成的这些属性。
  • Decorator 和 Proxy 的用途不同,但结构相似。两者都描述了如何提供对另一个对象的间接级别,并且实现保留对它们转发请求的对象的引用。
  • Decorator 允许您更改对象的皮肤。策略让你改变胆量。

本文来自转载,原文链接:

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注