【发布时间】:2010-10-05 01:46:17
【问题描述】:
我刚开始学习设计模式,我有两个关于装饰器的问题......
我想知道为什么装饰器模式建议装饰器实现它所装饰的组件的所有公共方法?
装饰器类不能只用来提供额外的行为,然后具体组件(传入它)只用来调用其他所有东西吗?
其次,如果您要装饰的具体组件没有抽象装饰器也可以派生的基类怎么办?
提前致谢!
【问题讨论】:
标签: design-patterns oop decorator
我刚开始学习设计模式,我有两个关于装饰器的问题......
我想知道为什么装饰器模式建议装饰器实现它所装饰的组件的所有公共方法?
装饰器类不能只用来提供额外的行为,然后具体组件(传入它)只用来调用其他所有东西吗?
其次,如果您要装饰的具体组件没有抽象装饰器也可以派生的基类怎么办?
提前致谢!
【问题讨论】:
标签: design-patterns oop 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
}
}
装饰器类不扩展其“装饰”类的基类。它是一个不同的类型,它有一个被装饰类的成员对象。因此,它必须实现相同的接口,如果只是调用装饰对象的相应方法。
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
}
}
可能值得为装饰类和装饰类定义一个接口(如果你的语言支持这样的东西)。这样您就可以在编译时检查装饰器是否实现了相同的接口。
interface IBase {
function foo();
function bar();
}
class Base implements IBase {
. . .
}
class Decorator implements IBase {
. . .
}
回复:@Yossi Dahan 的评论:我在维基百科文章中看到了歧义,但如果你仔细阅读,它确实说被装饰的组件是装饰器对象中的一个 字段,并且组件作为参数传递给装饰器构造函数。这与继承不同。
虽然维基百科文章确实说装饰器继承自组件,但您应该将其视为实现接口,正如我在上面的 PHP 示例中所示。装饰器仍然必须代理组件对象,如果它继承了它就不会。这允许装饰器装饰实现该接口的任何类的对象。
以下是 Gamma、Helm、Johnson 和 Vlissides 的“设计模式:可重用的面向对象软件的元素”的一些节选:
装饰器
意图
为对象附加额外的职责 动态的。装饰器提供了一个 子类化的灵活替代方案 用于扩展功能。
动机
... 一个装饰器符合的接口 它装饰的组件,使其 存在是透明的 组件的客户端。
参与者
- 装饰器 维护对 Component 对象的引用并定义接口 符合 Component 的接口。
【讨论】:
我想知道为什么装饰器模式建议装饰器实现它所装饰的组件的所有公共方法?
装饰器应该是它装饰的组件的替代品,具有额外的功能(“装饰”)。这只有在它完全实现了组件的接口时才会发生。
装饰器类不能只用来提供额外的行为,然后具体组件(传入它)只用来调用其他所有东西吗?
这对装饰器的实现方式做出了假设。你不能确定它所装饰的组件的整个公共接口是直接通过的。装饰器可能会在其实现中覆盖某些方法。
其次,如果您要装饰的具体组件没有抽象装饰器也可以派生的基类怎么办?
装饰器通常继承它们正在装饰的组件的类,而不是组件的基类。
【讨论】: