What is there so useful in the Decorator Pattern? My example doesn't work
- by Green
The book says:
The decorator pattern can be used to extend (decorate) the
functionality of a certain object
I have a rabbit animal. And I want my rabbit to have, for example, reptile skin. Just want to decorate a common rabbit with reptile skin.
I have the code. First I have abstract class Animal with everythig that is common to any animal:
abstract class Animal {
abstract public function setSleep($hours);
abstract public function setEat($food);
abstract public function getSkinType();
/* and more methods which for sure will be implemented in any concrete animal */
}
I create class for my rabbit:
class Rabbit extends Animal {
private $rest;
private $stomach;
private $skinType = "hair";
public function setSleep($hours) {
$this->rest = $hours;
}
public function setFood($food) {
$this->stomach = $food;
}
public function getSkinType() {
return $this->$skinType;
}
}
Up to now everything is OK. Then I create abstract AnimalDecorator class which extends Animal:
abstract class AnimalDecorator extends Animal {
protected $animal;
public function __construct(Animal $animal) {
$this->animal = $animal;
}
}
And here the problem comes. Pay attention that AnimalDecorator also gets all the abstract methods from the Animal class (in this example just two but in real can have many more).
Then I create concrete ReptileSkinDecorator class which extends AnimalDecorator. It also has those the same two abstract methods from Animal:
class ReptileSkinDecorator extends AnimalDecorator {
public function getSkinColor() {
$skin = $this->animal->getSkinType();
$skin = "reptile";
return $skin;
}
}
And finaly I want to decorate my rabbit with reptile skin:
$reptileSkinRabbit = ReptileSkinDecorator(new Rabbit());
But I can't do this because I have two abstract methods in ReptileSkinDecorator class. They are:
abstract public function setSleep($hours);
abstract public function setEat($food);
So, instead of just re-decorating only skin I also have to re-decorate setSleep() and setEat(); methods. But I don't need to.
In all the book examples there is always ONLY ONE abstract method in Animal class. And of course it works then. But here I just made very simple real life example and tried to use the Decorator pattern and it doesn't work without implementing those abstract methods in ReptileSkinDecorator class.
It means that if I want to use my example I have to create a brand new rabbit and implement for it its own setSleep() and setEat() methods. OK, let it be. But then this brand new rabbit has the instance of commont Rabbit I passed to ReptileSkinDecorator:
$reptileSkinRabbit = ReptileSkinDecorator(new Rabbit());
I have one common rabbit instance with its own methods in the reptileSkinRabbit instance which in its turn has its own reptileSkinRabbit methods. I have rabbit in rabbit. But I think I don't have to have such possibility.
I don't understand the Decarator pattern right way. Kindly ask you to point on any mistakes in my example, in my understanding of this pattern.
Thank you.