DECORATOR PATTERN — PHP

Uğur Müslim
3 min readDec 8, 2020

--

In this article, I’ll write about basic decorator pattern. This pattern is really enjoyable because it is like you wrap a present box and another one is in front of your eyes.

If you want to see the other patterns you can visit these below links.

So let’s start with a Team. For example you got a team with some stats and you want to calculate them with some default multipliers.

  • Strength : Multiplier = 3
  • Agility : Multiplier = 4
  • Intelligence : Multiplier = 5

Given stats will be multiplied with these default multipliers. Let’s do it;

There is a team class with setting above parameters for the sake of the example.

class Team
{

public $strength;
public $agility;
public $intelligence;

public function setStrength($stat) {
$this->strength = $stat;
return $this;
}

public function setAgility($stat) {
$this->agility = $stat;
return $this;
}

public function setIntelligence($stat) {
$this->intelligence = $stat;
return $this;
}
}

Let’s set team’s stats;

$team = new Team();
$team->setStrength(7);
$team->setAgility(6);
$team->setIntelligence(5);

Let’s say these classes are all linked to each other and their whole calculation will give us the power of the team.

$teamPower = ($team->strength * 3) + ($team->agility * 4) + ($team->intelligence * 5)

But this is not smooth enough. We can do better.

I will create an Interface to specify the contract of the classes I’ll create;

interface StatCalculator
{
public function weight(): int;

public function calculate(): int;
}

Then I will create a simple IntelligenceClass;

class IntelligenceClass implements StatCalculator
{
protected $stat;

public function __construct(int $stat)
{
$this->stat = $stat;
}

public function weight(): int
{
return 5;
}

public function calculate(): int
{
return $this->stat * $this->weight();
}
}

As you see I implemented StatCalculator Interface. This class is created just for the purpose of calculating a value with our given stat and default multiplier. We have two more classes like that but with a little difference.

class AgilityClass implements StatCalculator
{

protected $stat;
private $statCalculator;

public function __construct(StatCalculator $statCalculator, int $stat)
{
$this->stat = $stat;
$this->statCalculator = $statCalculator;
}

public function weight(): int
{
return 4;
}

public function calculate(): int
{
return ( $this->stat * $this->weight() ) + $this->statCalculator->calculate();
}
}

As you see I created Agility Class but with a little difference. I gave StatCalculator type value to construct for the purpose of giving the benefit of reaching to IntelligenceClass and its functions.

$teamPower = ( new AgilityClass(new IntelligenceClass($team->intelligence),$team->agility) )->calculate();

There is only one calculation for AgilityClass in here. But it will eventually trigger IntelligenceClass calculation method also.

So when we var_dump the value we must get (5 * 5) + (6 *4) = 49

var_dump($teamPower);
(int49)

So now we can go further with creating StrengthClass also.

class StrengthClass implements StatCalculator
{

protected $stat;
protected $statCalculator;

public function __construct(StatCalculator $statCalculator, int $stat)
{
$this->stat = $stat;
$this->statCalculator = $statCalculator;
}

public function weight(): int
{
return 3;
}

public function calculate(): int
{
return ( $this->stat * $this->weight() ) + $this->statCalculator->calculate();
}
}

As you see we did the same thing. So the function wil be like this.

$teamPower = (new StrengthClass( new AgilityClass(new IntelligenceClass($team->intelligence),$team->agility),$team->strength))->calculate();var_dump($teamPower);
int(70)

As you see the code started from Strength, then went to Agility calculate function and from there it went to Intelligence Class. We don’t have to stop here. We can put a calculate power in our Team class so it will be tidy and more understandable.

class Team
{

..........

public function calculatePower(): int
{
return ( new StrengthClass(new AgilityClass(new IntelligenceClass($this->intelligence), $this->agility), $this->strength) )->calculate();

}
}

So we can call this function from wherever we want like this;

$team = new Team();
$team->calculatePower();

This was a simple example for decorator pattern and maybe it is not the perfect example. But the main concept is pretty straight forward so I think anyone who reads this article will get the pattern’s worokflow.

There is good video about this pattern. If you have time you can look at it;

--

--

Uğur Müslim
Uğur Müslim

Written by Uğur Müslim

Software developer, guitar player, drinks mostly tea and water. Lately reads history books. Trying to get away from fiction.

Responses (2)