The Decorator Design Pattern

The Decorator Design Pattern

The Decorator Pattern is a structural design pattern that has the ability to add behavior to an existing class dynamically.

We can use it to add additional features to objects without the need to heavily modify the underlying code using them.

This pattern avoids using inheritance to add functionality that is not required. It prevents us to break the Open-Closed SOLID Principle: "An object or component should be open for extension but closed from modification". So, if we inherit from a class that we need to modify it several times to add functionality, then we're breaking this principle. When we use decorator, we extend that functionality to other classes.

So, ask yourself: If I inherit from that class do I really need to pull in the entirety of that functionality, or do I simply need to adjust the behavior of one or two methods? If that is the case then maybe you can refer to the Decorator Pattern.

So here's the pattern explained on PHP. We're going to use a Coffee Service implementation example, where you can order a single coffee and you also have the option to add milk, cinnamon, or both, then we can get the final cost and description. The idea is that we can understand this pattern by using the analogy of decorating the coffee.

  1. First we need an interface, this is important because every Decorator Class needs to implement the same interface as the core class:
interface CoffeeService {

    public function getCost();

    public function getDescription();

}
  1. We create the basic class, in our case is the SingleCoffee Class:
class SingleCoffee implements CoffeeService{

    public function getCost(){
        return 15;
    }

    public function getDescription(){
        return 'Single Coffee';
    }

}
  1. Then we create our first Decorator, it must implement the same interface as the SingleCoffee Class, and the constructor must accept an instance or implementation of the same contract:
class Milk implements CoffeeService {

    protected $coffeeService;

    function __construct(CoffeeService $coffeeService){
        $this->coffeeService = $coffeeService;
    }

    public function getCost(){
        return 5 + $this->coffeeService->getCost();
    }

    public function getDescription(){
        return $this->coffeeService->getDescription() . ', with milk';
    }

}
  1. We create our final decorator class:
class Cinnamon implements CoffeeService {

    protected $coffeeService;

    function __construct(CoffeeService $carService){
        $this->coffeeService = $coffeeService;
    }

    public function getCost(){
        return 2 + $this->coffeeService->getCost();
    }

    public function getDescription(){
        return $this->coffeeService->getDescription() . ', with cinammon';
    }

}

Finally, to run our code, create an instance of our basic class and wrap it with the decorators that we want:

$coffeeService = new Cinnamon(new Milk(new SingleCoffee));

echo $coffeeService->getCost();

echo $coffeeService->getDescription();

The output of this would be:

22 Single Coffee, with milk, with cinnamon

You can run and view the full code here: codepad.org/at37vpqW

And that's all! Painless code right?