Pius Adams Ijachi
3 min readJan 9, 2024

DECORATOR PATTERN

Hi everyone, Today, I want to talk about the decorator design pattern, what it is, when to use it, and what are its advantages. I will also show you an example of how I implemented it in PHP.

The decorator design pattern is a structural design pattern that allows you to add new functionality to an existing object without changing its structure. This is achieved by wrapping the original object with another object that implements the same interface and delegates all the requests to it. The wrapper object can then add some extra behavior before or after the original object’s method.

The decorator design pattern is useful when you want to extend the behavior of an object dynamically at run time, without using inheritance or modifying the source code. For example, you can use the decorator pattern to add logging, caching, validation, or encryption features to an existing class.

Let’s see how I used the decorator pattern in a simple example.

Suppose I have a transport mode interface that defines two methods: getDescription() and calculatePrice(). I have two concrete classes that implement this interface: Air and Land. Air represents traveling by plane and Land represents traveling by car.

Now, suppose I want to add some optional features to these transport modes, such as comfort features (like extra legroom or entertainment system) or luggage (like extra baggage allowance or priority boarding). Instead of creating subclasses for each combination of features, I can use the decorator pattern to create wrapper classes that implement the transport mode interface and add these features dynamically.

I have created two decorator classes: ComfortFeaturesDecorator and LuggageDecorator. They both take a transport mode object as a parameter in their constructor and store it as a property. They also implement the getDescription() and calculatePrice() methods by calling the same methods on the wrapped object and adding some extra logic.

Here is the code for the implementation:

// component
<?php
interface TransportModeInterface
{
public function calculatePrice(): int;
public function getDescription(): string;}// concrete component (implementation)
<?php
class Land implements TransportModeInterface
{
public function calculatePrice(): int
{
return 50;
}
public function getDescription(): string
{
return "Land";
}
}
<?php
class Air implements TransportModeInterface
{
public function calculatePrice(): int
{
return 100;
}
public function getDescription(): string
{
return "Air";
}
}
// decorator
<?php
abstract class TransportDecorator implements TransportModeInterface
{
protected TransportModeInterface $transportMode; public function __construct(TransportModeInterface $transportMode)
{
$this->transportMode = $transportMode;
}
public function calculatePrice(): int
{
return $this->transportMode->calculatePrice();
}
public function getDescription(): string
{
return $this->transportMode->getDescription();
}
}
// docorator implementation
<?php
class ComfortFeaturesDecorator extends TransportDecorator
{
public function calculatePrice(): int
{
return $this->transportMode->calculatePrice() + 10;
}
public function getDescription(): string
{
return $this->transportMode->getDescription() . ' with comfort features';
}
}
class LuggageDecorator extends TransportDecorator
{
public function calculatePrice(): int
{
return $this->transportMode->calculatePrice() + 5;
}
public function getDescription(): string
{
return $this->transportMode->getDescription() . ' with luggage space';
}
}
// Usage
$transportMode = new \Decorator\Modes\Air();
echo $transportMode->getDescription() . " " . $transportMode->calculatePrice() . "\n";$transportMode = new \Decorator\Modes\Land($transportMode);echo $transportMode->getDescription() . " " . $transportMode->calculatePrice() . "\n";$transportMode = new \Decorator\Decorators\ComfortFeaturesDecorator($transportMode);
$transportMode = new \Decorator\Decorators\LuggageDecorator($transportMode);
echo $transportMode->getDescription() . " " . $transportMode->calculatePrice() . "\n";

As you can see, I can create different combinations of transport modes and features by wrapping them with decorators. The output of this code is:

Air 100
Land + Air 150
Land + Air + Comfort Features + Luggage 200

I hope you enjoyed this blog post and learned something new about the decorator design pattern. If you want to see the full code of this example, you can check out my GitHub link here: https://github.com/Adams-Ijachi/design-patterns/tree/main/Decorator

Below is a video that explains it much better lol😊

https://www.youtube.com/watch?app=desktop&v=GCraGHx6gso&pp=ygUQI2Rlc3NpZ25wYXR0ZXJucw%3D%3D

Thanks for reading and stay tuned for more posts about coding and design patterns!

Pius Adams Ijachi
Pius Adams Ijachi

No responses yet