题
我刚刚开始学习设计模式,我有两个与装饰者有关的问题...
我想知道为什么装饰器图案暗示装饰器实现了它装饰的所有组件的所有公共方法?
装饰班不能仅仅用于提供其他行为,然后才能使用混凝土组件(传递到其中)来调用所有其他行为?
其次,如果您要装饰的混凝土组件没有抽象装饰器也可以衍生的基类怎么办?
提前致谢!
解决方案
我认为您有误解的装饰师。您正在考虑一个简单的情况,即扩展具有其他功能的混凝土类。在这种情况下,是的,在大多数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的评论:我看到了Wikipedia文章中的歧义,但是如果您仔细阅读,它确实说要装饰的组件是一个 场地 在装饰器的对象中,该组件作为参数传递给了装饰构造函数。这与继承不同。
尽管Wikipedia文章确实说Decorator从组件中继承,但您应该认为这是实现界面,如我在上面的PHP示例中所示。装饰器仍然必须代理组件对象,如果它继承了该对象。这使装饰器可以装饰 任何 实现该接口的类。
以下是来自Gamma,Helm,Johnson和Vlissides的“设计模式:可重复使用对象软件的元素”的一些摘录:
装饰师
意图
动态地将其他职责附加到对象上。装饰器为扩展功能的子类提供了灵活的替代方案。
动机
...装饰符符合其装饰组件的界面,以使其具有透明的组件客户端。
参与者
- Decorator维护对组件对象的引用,并定义与组件接口相符的接口。
其他提示
我想知道为什么装饰器图案暗示装饰器实现了它装饰的所有组件的所有公共方法?
装饰器应置于其装饰组件的替换中,并具有额外的功能(“装饰”)。只有在完全实现组件的接口时,才会发生这种情况。
装饰班不能仅仅用于提供其他行为,然后才能使用混凝土组件(传递到其中)来调用所有其他行为?
这是关于如何实现装饰器的假设。您无法确定它装饰的组件的整个公共界面正在直接通过。装饰器可能会在其实现中覆盖某些方法。
其次,如果您要装饰的混凝土组件没有抽象装饰器也可以衍生的基类怎么办?
装饰器通常继承他们正在装饰的组件类,而不是组件的基础。