🚨 ¡Nueva review! 🔇 Los mejores cascos con ANC del mercado: los Sony WH-1000XM4 . ¡Échale un ojo! 👀

El patrón de diseño Chain of Responsibility

Pasa la patata caliente hasta que alguien se queme.

Escrito por domin el 23 de noviembre de 2025

🔗 El patrón Chain of Responsibility: La cadena de mando

El patrón Chain of Responsibility, es un patrón de comportamiento que tiene una misión clara: evitar acoplar el emisor de una petición a su receptor, dando a más de un objeto la oportunidad de manejarla.

El problema que resuelve es este:
¿Cómo puedes hacer que una solicitud sea atendida por el objeto adecuado sin que el emisor sepa quién es, y sin tener un if/else gigante y monstruoso?

La respuesta es encadenar los objetos receptores y pasar la solicitud a lo largo de la cadena hasta que un objeto la maneje.

Diagrama del Patrón Chain of Responsibility mostrando una cadena de manejadores.

🔗 1. Un ejemplo sencillo: El soporte técnico

Imagina que llamas a tu compañía de internet porque no te va el WiFi (La petición):

  1. Nivel 1 (robot): Te atiende una máquina. “¿Ha probado a reiniciar?”. Si no funciona, te pasa al siguiente nivel.
  2. Nivel 2 (operador humano): Te atiende una persona. Revisa tu factura. Si es un problema técnico complejo, te pasa al siguiente nivel.
  3. Nivel 3 (ingeniero): Te atiende un técnico especializado. Este sí sabe qué cable tocar.

Concepto (analogía)

Rol en Chain of Responsibility

Tarea principal

Tú (cliente)

Cliente

Inicia la petición sin saber quién la resolverá finalmente.

Robot / Operador / Ingeniero

Manejadores concretos

Deciden si procesan la petición o se la pasan al siguiente compañero.

🛠️ 2. Los tres pilares del patrón Chain of Responsibility

Para montar esta cadena, necesitamos tres piezas clave:

1. El manejador (handler)

2. Manejadores concretos

3. El cliente

🤔 1. ¿Qué pasa si la petición llega al final de la cadena y nadie la ha atendido?

💾 3. El ejemplo clásico: Middleware en web

Un ejemplo muy común son los Middlewares en frameworks web (como Laravel o Express). Cuando llega una petición HTTP:

  1. Middleware de Auth: ¿Está logueado? Si no, error. Si sí, pasa al siguiente.
  2. Middleware de Validación: ¿Los datos son correctos? Si no, error. Si sí, pasa al siguiente.
  3. Controlador: Procesa la petición y devuelve la respuesta.

🤔 2. ¿Cuál es la principal ventaja de este patrón respecto a un switch/case gigante?

✅ 4. ¿Por qué usarlo?

  1. Desacoplamiento: El emisor no necesita conocer la cadena completa ni quién resolverá su problema.
  2. Flexibilidad: Puedes añadir o quitar eslabones de la cadena dinámicamente.
  3. Principio de responsabilidad única: Cada clase se encarga de una sola cosa (o de pasar la bola).

❌ 5. Desventaja a considerar

🤔 3. ¿Es obligatorio que todos los manejadores pasen la petición al siguiente?

💡 6. Conclusión

El Chain of Responsibility es ideal para flujos de trabajo secuenciales donde varios objetos pueden tener algo que decir. Convierte un árbol de decisiones complejo en una lista ordenada y limpia de objetos que colaboran (o se pasan el marrón) entre sí.

🧠 7. Ejemplo práctico en PHP

Vamos a implementar el sistema de soporte técnico del que hablábamos.

<?php

// 🔹 1. La Interfaz del Manejador (Handler)
abstract class SoporteHandler
{
    protected ?SoporteHandler $siguiente = null;

    public function setSiguiente(SoporteHandler $handler): SoporteHandler
    {
        $this->siguiente = $handler;
        // Devolvemos el handler para poder encadenar: $a->setSiguiente($b)->setSiguiente($c)
        return $handler;
    }

    public function manejar(string $problema): ?string
    {
        if ($this->siguiente) {
            return $this->siguiente->manejar($problema);
        }

        return null; // Nadie pudo atenderlo
    }
}

// 🔹 2. Manejadores Concretos
class Robot extends SoporteHandler
{
    public function manejar(string $problema): ?string
    {
        if ($problema === 'basico') {
            return "🤖 Robot: He reiniciado tu router. ¿Funciona? (Problema resuelto)";
        }
        echo "🤖 Robot: No sé resolver esto, paso al humano...\n";
        return parent::manejar($problema);
    }
}

class OperadorHumano extends SoporteHandler
{
    public function manejar(string $problema): ?string
    {
        if ($problema === 'facturacion') {
            return "👨‍💼 Operador: He corregido tu factura. (Problema resuelto)";
        }
        echo "👨‍💼 Operador: Esto es muy técnico, paso al ingeniero...\n";
        return parent::manejar($problema);
    }
}

class Ingeniero extends SoporteHandler
{
    public function manejar(string $problema): ?string
    {
        if ($problema === 'fuego') {
            return "👷 Ingeniero: He apagado el fuego del servidor. (Problema resuelto)";
        }
        echo "👷 Ingeniero: Ni yo sé qué pasa...\n";
        return parent::manejar($problema);
    }
}

// 🔹 3. Cliente (Configuración y Uso)
$robot = new Robot();
$operador = new OperadorHumano();
$ingeniero = new Ingeniero();

// Montamos la cadena: Robot -> Operador -> Ingeniero
$robot->setSiguiente($operador)->setSiguiente($ingeniero);

// Probamos
echo "--- Intento 1: Problema Básico ---\n";
echo $robot->manejar('basico') . "\n\n";

echo "--- Intento 2: Problema de Facturación ---\n";
echo $robot->manejar('facturacion') . "\n\n";

echo "--- Intento 3: Fuego en el servidor ---\n";
echo $robot->manejar('fuego') . "\n\n";

echo "--- Intento 4: Alienígenas ---\n";
$resultado = $robot->manejar('alienigenas');
if ($resultado === null) {
    echo "❌ Nadie pudo resolver el problema de los alienígenas.\n";
}

// 🖥️ Salida:
// --- Intento 1: Problema Básico ---
// 🤖 Robot: He reiniciado tu router. ¿Funciona? (Problema resuelto)
//
// --- Intento 2: Problema de Facturación ---
// 🤖 Robot: No sé resolver esto, paso al humano...
// 👨‍💼 Operador: He corregido tu factura. (Problema resuelto)
//
// --- Intento 3: Fuego en el servidor ---
// 🤖 Robot: No sé resolver esto, paso al humano...
// 👨‍💼 Operador: Esto es muy técnico, paso al ingeniero...
// 👷 Ingeniero: He apagado el fuego del servidor. (Problema resuelto)
//
// --- Intento 4: Alienígenas ---
// 🤖 Robot: No sé resolver esto, paso al humano...
// 👨‍💼 Operador: Esto es muy técnico, paso al ingeniero...
// 👷 Ingeniero: Ni yo sé qué pasa...
// ❌ Nadie pudo resolver el problema de los alienígenas.

EA, ¡saluditos y nos vemos en los bares! 🍻