装饰设计模式

时间:2009-02-03 00:46:01

标签: design-patterns oop decorator

我刚开始学习设计模式,我有两个与装饰师有关的问题......

我想知道为什么装饰器模式表明装饰器实现了它所装饰的组件的所有公共方法?

装饰器类不能仅用于提供额外的行为,然后具体的组件(传递给它)只是用于调用其他所有内容吗?

其次,如果要装饰的具体组件没有抽象装饰器也可以派生出来的基类怎么办?

提前致谢!

2 个答案:

答案 0 :(得分:15)

我觉得你误解了装饰师。您正在考虑使用其他功能扩展具体类的简单情况。在这种情况下,在大多数OO语言中,是派生类可以简单地允许其超类处理任何未实现的方法。

class Base {

  function foo() {
    return "foo";
  }

  function bar() {
    return "bar";
  }

}

// Not what we think of as a Decorator,
// really just a subclass.
class Decorator extends Base {

  // foo() inherits behavior from parent Base class 

  function bar() {
    return parent::bar() . "!"; // add something
  }

}

Decorator类不会扩展其“装饰”类的基类。它是一个不同的类型,它具有装饰类的成员对象。因此,它必须实现相同的接口,如果只是为了调用装饰对象的相应方法。

class Decorator { // extends nothing
  protected $base;

  function __construct(Base $base) {
    $this->base = $base;
  }

  function foo() {
    return $base->foo();
  }

  function bar() {
    return $base->foo() . "!"; // add something
  }

}

为装饰类和Decorator类定义接口(如果您的语言支持这样的东西)可能是值得的。这样你就可以在编译时检查Decorator是否实现了相同的接口。

interface IBase {
  function foo();
  function bar();
}

class Base implements IBase {
  . . .
}

class Decorator implements IBase {
  . . .
}

回复:@Yossi Dahan的评论:我看到维基百科文章中含糊不清,但是如果你仔细阅读它确实说装饰的组件是装饰器对象中的字段,那就是component作为参数传递给装饰器构造函数。这与继承不同。

虽然维基百科的文章确实说装饰器继承自组件,但您应该将其视为实现接口,正如我在上面的PHP示例中所示。装饰器仍然需要代理组件对象,如果它继承了它就不会。这允许装饰器装饰实现该接口的任何类的对象。

以下是Gamma,Helm,Johnson和Vlissides的“设计模式:可重复使用的面向对象软件的元素”的一些摘录:

  

装饰

     

意图

     

将附加职责附加到对象   动态。装饰者提供了一个   子类化的灵活替代方案   用于扩展功能。

     

动机

     

...   装饰器符合界面   它装饰的组件,以便它   存在是透明的   组件的客户。

     

参与者

     
      
  • 装饰   维护对Component对象的引用并定义接口   符合Component的界面。
  •   

答案 1 :(得分:3)

  

我想知道为什么装饰器模式表明装饰器实现了它所装饰的组件的所有公共方法?

装饰器应该是它装饰的组件的替代品,具有额外的功能(“装饰”)。只有在完全实现组件的接口时才会发生这种情况。

  

装饰器类不能仅用于提供额外的行为,然后具体的组件(传递给它)只是用于调用其他所有内容吗?

这假设了装饰器的实现方式。您无法确定它所装饰的组件的整个公共接口是否直接传递。装饰器可能会覆盖其实现中的某些方法。

  

其次,如果要装饰的具体组件没有抽象装饰器也可以派生出来的基类怎么办?

装饰器通常继承他们正在装饰的组件类,而不是组件的基础。