在PHP中实现Decorator模式的两种不同方式


Two different ways to implement Decorator pattern in PHP

在做一些关于Decorator模式的教程时,我遇到了两种不同的实现。

实现1(简称I1)

实现2(简称I2)

总之,

I1的父装饰器类实现了原对象的接口(在本例中,PropertyDecorator类实现了PropertyInterface)。原对象Property也实现了PropertyInterface)。

I2的父装饰器类没有实现原始对象的接口(在这个例子中,Decorator_Wrapper没有实现Cupcake接口)。事实上,根本就没有CupcakeInterface)。

这仅仅是理解和实现Decorator模式的个人偏好吗?或者一个是错的,一个是对的?

这取决于你的需要。让我们看看:

抽象类

  • 可以提供抽象方法。
  • 可以提供真实的函数和变量
  • 可以扩展。但是一个类只能继承一个父类。

界面

  • 可以提供抽象方法。
  • 一个类可以实现多个接口

我通常更喜欢使用基抽象类,因为我也可以声明一些基本函数,因为你可以有很多不同类型的装饰器具有类似的功能。方法无论如何都可以被重写+你可以实现一些接口。

class Decorator extends Decorator_Wrapper implements Interface1, Inteface2 {
  public function __construct(){
    parent::__construct() ; // Here you could perform some basic decorator actions. It is an advantage compared to interfaces.
  }
}

当您希望在不扩展类本身的情况下扩展类实例的功能(因此,不影响该类的其他实例)时,可以使用Decorator模式。

它是一种运行时的扩展,它非常有用,因为它允许你在运行时自定义对象的行为。你甚至可以用它"模拟"多重继承。

因为你的两个例子都做到了这一点,所以都是正确的。不需要装饰器来实现基本接口或扩展原始对象。


然而…


如果装饰器没有实现基接口,它可能无法与原始类互换使用。

如果你不能在任何地方"安全地"使用装饰器,这可能会破坏使用它的目的。

的例子:

interface FooInterface {
    public function scare();
}
class Foo implements FooInterface {
    protected $boo = 'boo';
    public function scare() { echo $this->boo; }
}
class FooBar {
    public function __construct(FooInterface $foo) {
       $this->foo = $foo;
    }
    public function scareAlot() { 
        echo strtoupper($this->foo->scare());
    }
}

class INeedFoo {
    public static function gimmeFoo(FooInterface $foo) {}
}

$foo = new Foo();
$fooBar = new FooBar($foo);
INeedFoo::gimmeFoo($foo); //Works
INeedFoo::gimmeFoo($fooBar); //Does not Work

此外,如果你实现基接口或扩展基类,可能更容易在彼此之上添加多个装饰器,但是……您还可能最终得到大量复制的功能。