Patrón Decorator
En muchas ocasiones necesitamos añadir funcionalidades extra a un objeto sin modificar su código original.
La solución rápida suele ser crear nuevas subclases con variantes, pero esto puede volverse inmanejable.
El patrón Decorator nos permite envolver un objeto con capas adicionales de comportamiento, como si fueran buffs mágicos en un RPG 🧙♂️.
❌ El problema
Imaginemos un Mago que puede lanzar un hechizo básico de magia.
Si queremos que a veces el hechizo tenga fuego, otras veces hielo, y en ocasiones hasta veneno, podemos caer en la tentación de hacer muchas subclases:
MagoConFuegoMagoConHieloMagoConVenenoMagoConFuegoYVeneno- … y así hasta el infinito 😵💫.
Esto rompe la simplicidad y vuelve difícil mantener el código.
Veamos una primera versión ingenua:
<?php
class Mago {
private string $nombre;
public function __construct(string $nombre) {
$this->nombre = $nombre;
}
public function lanzarHechizo(string $enemigo): void {
echo "✨ {$this->nombre} lanza un simple rayo mágico contra $enemigo.\n";
}
}
$mago = new Mago("Gandalf");
$mago->lanzarHechizo("Orco Malvado");
✅ La solución: Patrón Decorator
Con el patrón Decorator podemos envolver al Mago con distintos efectos mágicos sin modificar su clase original.
Cada decorador añade su propia capa de poder, como si fuesen items mágicos equipables.
1️⃣ Definimos la interfaz base
<?php
interface Hechizo {
public function lanzar(string $enemigo): void;
}
2️⃣ Creamos el hechizo básico del mago
<?php
class HechizoBasico implements Hechizo {
private string $nombre;
public function __construct(string $nombre) {
$this->nombre = $nombre;
}
public function lanzar(string $enemigo): void {
echo "✨ {$this->nombre} lanza un rayo mágico a $enemigo.\n";
}
}3️⃣ Creamos el decorador base
<?php
abstract class HechizoDecorator implements Hechizo {
protected Hechizo $hechizo;
public function __construct(Hechizo $hechizo) {
$this->hechizo = $hechizo;
}
public function lanzar(string $enemigo): void {
$this->hechizo->lanzar($enemigo);
}
}4️⃣ Decoradores concretos (fuego, hielo, veneno…)
<?php
class HechizoFuego extends HechizoDecorator {
public function lanzar(string $enemigo): void {
parent::lanzar($enemigo);
echo "🔥 ¡El fuego envuelve a $enemigo!\n";
}
}
class HechizoHielo extends HechizoDecorator {
public function lanzar(string $enemigo): void {
parent::lanzar($enemigo);
echo "❄️ $enemigo queda congelado en hielo.\n";
}
}
class HechizoVeneno extends HechizoDecorator {
public function lanzar(string $enemigo): void {
parent::lanzar($enemigo);
echo "☠️ $enemigo sufre daño por veneno.\n";
}
}5️⃣ Uso del patrón Decorator
<?php
$mago = new HechizoBasico("Gandalf");
// Hechizo simple
$mago->lanzar("Orco Malvado");
// Hechizo con fuego
$magoFuego = new HechizoFuego($mago);
$magoFuego->lanzar("Orco Malvado");
// Hechizo con fuego y veneno
$magoFuegoVeneno = new HechizoVeneno(new HechizoFuego($mago));
$magoFuegoVeneno->lanzar("Orco Malvado");
// Hechizo con fuego, hielo y veneno (full combo)
$magoFull = new HechizoVeneno(new HechizoHielo(new HechizoFuego($mago)));
$magoFull->lanzar("Orco Malvado");🏁 Conclusión
El patrón Decorator nos permite:
- ✨ Añadir comportamientos de forma dinámica sin tocar la clase original.
- 🔄 Combinar efectos fácilmente (fuego + hielo + veneno).
- 📐 Cumplir con el principio abierto/cerrado (OCP).
La próxima vez que quieras extender funcionalidades sin multiplicar subclases, recuerda al Mago que potencia sus hechizos con Decorator 🧙♂️🔥❄️☠️.
Con esto completamos otro capítulo de nuestra saga de patrones.
Que tus clases sean abiertas a la extensión y cerradas a los bugs 🧙♂️✨.