2
votes

While doing some tutorials on Decorator pattern, I've encountered two different implementations.

Implementation 1 (referred to as I1)

Implementation 2 (referred to as I2)

In short,

I1's parent decorator class implements original object's interface (In the example, class PropertyDecorator implements PropertyInterface. The original object Property implements PropertyInterface as well).

I2's parent decorator class DOES NOT implement original object's interface (In the example, Decorator_Wrapper does not implements Cupcake interface. In fact, there is not even CupcakeInterface at all).

My question is,

Is this merely a personal preference of understanding and implementing Decorator pattern? or one is wrong and one is right?

2

2 Answers

1
votes

Just depends on your needs. Let's see:

Abstract class

  • Can provide abstract methods.
  • Can provide real functions and variables.
  • Can be extended. But a class can extend only 1 parent.

Interface

  • Can provide abstract methods.
  • A class may implement several interfaces.

I generally would prefer using a base abstract class, because I can declare some basic functions as well, since you could have a lot of different types of decorators with similar functionality. Methods can be overriden anyways + you can implement some interfaces.

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.
  }
}
0
votes

The Decorator pattern is used when you wish to extend the functionality of an instance of a class without extending the class itself (thus, not affecting other instances of said class).

It's kind of an extension at runtime and it's pretty useful since it lets you customize the behavior of an object at runtime. You can even "simulate" multiple inheritance with it.

Since both your examples accomplish this, both are correct. There is no need for a decorator to implement the base interface or extend the original object.


HOWEVER...


If the decorator does not implement the base interface, it MIGHT not be able to be used interchangeably with the original class.

Which might defeat the purpose of using the decorator if you can't use it everywhere "safely".

Example:

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

Also, if you implement the base interface or extend the base class it might be easier to add multiple decorators on top of eachother but ... you may also end up with a lot of replicated functionality.