Il Decorator Design Pattern è un pattern strutturale che permette di aggiungere nuove funzionalità a un oggetto esistente senza modificare il suo codice. Questo pattern è utile quando si desidera estendere la funzionalità di un oggetto in modo dinamico, permettendo così di evitare l’overloading del codice o l’uso di classi troppo complesse.
Invece di modificare il comportamento di una classe direttamente, il Decorator Pattern permette di “decorare” un oggetto con nuove responsabilità, creando una relazione di composizione tra oggetti, dove uno decoratore incapsula l’oggetto originario e ne estende le funzionalità.
Esempio di Implementazione in PHP
In questo esempio, implementeremo una classe base che rappresenta un oggetto semplice e successivamente aggiungeremo dei decoratori per estenderne le funzionalità.
Immaginiamo di avere una classe Pizza e di voler aggiungere vari ingredienti come decoratori (es. formaggio extra, pomodoro, ecc.).
1. Creazione dell’oggetto base
La classe base Pizza rappresenta un oggetto di base che può essere decorato da altri oggetti.
class Pizza {
public function getDescription(): string {
return "Pizza base";
}
public function cost(): float {
return 5.00;
}
}
2. Creazione del decoratore astratto
Il decoratore astratto estende la classe Pizza e rappresenta una base per i decoratori concreti. Ogni decoratore deve implementare i metodi getDescription e cost.
abstract class PizzaDecorator extends Pizza {
protected $pizza;
public function __construct(Pizza $pizza) {
$this->pizza = $pizza;
}
abstract public function getDescription(): string;
abstract public function cost(): float;
}
3. Creazione dei decoratori concreti
Ogni decoratore concreto aggiungerà una funzionalità specifica all’oggetto Pizza originale, come ad esempio aggiungere un ingrediente.
class CheeseDecorator extends PizzaDecorator {
public function getDescription(): string {
return $this->pizza->getDescription() . ", con formaggio extra";
}
public function cost(): float {
return $this->pizza->cost() + 2.00;
}
}
class TomatoDecorator extends PizzaDecorator {
public function getDescription(): string {
return $this->pizza->getDescription() . ", con pomodoro";
}
public function cost(): float {
return $this->pizza->cost() + 1.50;
}
}
4. Utilizzo dei decoratori
Ora possiamo combinare i vari decoratori per creare una pizza personalizzata, aggiungendo funzionalità all’oggetto Pizza originale in modo dinamico.
$pizza = new Pizza();
$pizzaConFormaggio = new CheeseDecorator($pizza);
$pizzaConPomodoro = new TomatoDecorator($pizzaConFormaggio);
echo $pizzaConPomodoro->getDescription(); // Output: Pizza base, con formaggio extra, con pomodoro
echo $pizzaConPomodoro->cost(); // Output: 8.50
Conclusioni
Il Decorator Pattern consente di aggiungere comportamenti o funzionalità a oggetti esistenti in modo flessibile e senza modificare la classe originale. Questo è particolarmente utile quando si vuole evitare una proliferazione di classi per combinare diverse funzionalità. In PHP, l’uso di decoratori consente di estendere facilmente un oggetto senza dover cambiare il suo codice, seguendo il principio di Open/Closed Principle della SOLID.