我刚开始学习设计模式,我有两个与装饰师有关的问题......
我想知道为什么装饰器模式表明装饰器实现了它装饰的组件的所有公共方法?
装饰器类不能只用于提供额外的行为,然后具体组件(传递给它)只是用于调用其他所有内容吗?
其次,如果要装饰的具体组件没有抽象装饰器也可以派生出来的基类怎么办?
提前致谢!
我觉得你误解了Decorator.您正在考虑使用其他功能扩展具体类的简单情况.在这种情况下,在大多数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的评论:我在维基百科文章中看到了歧义,但如果你仔细阅读它确实说装饰的组件是装饰器对象中的一个字段,并且该组件作为参数传递给装饰器构造函数.这与继承不同.
虽然维基百科文章确实说装饰器继承自组件,但您应该将其视为实现接口,正如我在上面的PHP示例中所示.装饰器仍然需要代理组件对象,如果它继承了它就不会.这允许装饰器装饰实现该接口的任何类的对象.
以下是Gamma,Helm,Johnson和Vlissides的"设计模式:可重复使用的面向对象软件的元素"的一些摘录:
装饰意图
动态地将附加职责附加到对象.装饰器为子类化提供了灵活的替代扩展功能.
动机
...装饰器符合它装饰的组件的接口,因此它的存在对组件的客户端是透明的.
参与者
Decorator维护对Component对象的引用,并定义符合Component接口的接口.