Patrones de Diseño en PHP: Técnicas Avanzadas con Ejemplos de Código
Los patrones de diseño son soluciones probadas para problemas típicos que surgen durante el desarrollo de software. Si ya has dominado los patrones básicos (Singleton, Factory, Observer), es hora de pasar al siguiente nivel. En este artículo, cubriremos cuatro patrones de comportamiento avanzados en PHP: Strategy, Command, State y Chain of Responsibility. Aprenderás cómo ayudan a escribir código flexible, mantenible y escalable.
1. Patrón Strategy
El patrón Strategy te permite definir una familia de algoritmos, encapsular cada uno y hacerlos intercambiables. Esto es especialmente útil cuando tienes múltiples formas de realizar la misma tarea y quieres cambiar fácilmente entre ellas sin modificar la clase principal.
Cuándo usarlo:
- Tienes varias variantes de algoritmo que pueden cambiar en tiempo de ejecución.
- Quieres evitar construcciones condicionales voluminosas (if-else o switch).
- Los algoritmos pueden reutilizarse en diferentes partes de la aplicación.
Ejemplo: sistema de cálculo de costos de envío
Imagina que tienes una tienda en línea y el costo de envío depende del transportista seleccionado: Correos de Rusia, DHL o un servicio de mensajería.
<?php
// Interfaz Strategyinterface ShippingStrategy { public function calculate(float $weight, float $distance): float;}
// Estrategias concretasclass RussianPostShipping implements ShippingStrategy { public function calculate(float $weight, float $distance): float { return ($weight * 0.5) + ($distance * 0.1); }}
class DHLShipping implements ShippingStrategy { public function calculate(float $weight, float $distance): float { return ($weight * 1.2) + ($distance * 0.3) + 10; }}
class CourierShipping implements ShippingStrategy { public function calculate(float $weight, float $distance): float { return ($weight * 0.8) + ($distance * 0.2) + 5; }}
// Contextoclass Order { private float $weight; private float $distance; private ShippingStrategy $strategy;
public function __construct(float $weight, float $distance, ShippingStrategy $strategy) { $this->weight = $weight; $this->distance = $distance; $this->strategy = $strategy; }
public function setStrategy(ShippingStrategy $strategy): void { $this->strategy = $strategy; }
public function getShippingCost(): float { return $this->strategy->calculate($this->weight, $this->distance); }}
// Uso$order = new Order(2.5, 100, new RussianPostShipping());echo "Envío por Correos de Rusia: " . $order->getShippingCost() . " rub.";
$order->setStrategy(new DHLShipping());echo "Envío por DHL: " . $order->getShippingCost() . " rub.";?>En este ejemplo, cambiamos fácilmente el algoritmo de cálculo de costos sin tocar la clase Order. Agregar un nuevo transportista simplemente implica crear una nueva clase que implemente la interfaz ShippingStrategy.
2. Patrón Command
El patrón Command convierte las solicitudes en objetos, lo que permite parametrizar clientes con diferentes solicitudes, ponerlas en cola, registrarlas o admitir operaciones de deshacer.
Cuándo usarlo:
- Necesitas implementar operaciones de deshacer y rehacer.
- Necesitas poner en cola operaciones o ejecutarlas de forma asíncrona.
- Quieres desacoplar el emisor de una solicitud de su receptor.
Ejemplo: editor de texto con funcionalidad de deshacer
<?php
// Interfaz Commandinterface Command { public function execute(): void; public function undo(): void;}
// Receptorclass