🚨 ¡Nueva review! ✨ Mi ratón favorito para programar: el Logitech MX Master 3S . ¡Échale un ojo! 👀

El Patrón Composite: La Estructura de Cajas y Objetos

Trata a un objeto individual y a un grupo de objetos de la misma manera.

Escrito por domin el 28 de octubre de 2025

📦 El Patrón Composite: Organiza la Jerarquía como un Profesional

El Patrón Composite es uno de los 23 patrones de diseño GangOfFour y resuelve un problema muy común:
¿Cómo puedes tratar un objeto individual y un grupo de objetos de la misma forma, sin que tu código se vuelva una locura de condiciones if?

La respuesta está en que todos tengan un contrato igual para que todos se comporten de la misma manera.

📦 1. La Analogía “Para Dummies”: La Caja de Mudanza

Imagina que tienes una lista de tareas para una mudanza: calcular el peso total.

Elemento (Analogía)

Rol en Composite

Comportamiento del Peso

Libro, Taza

Hoja (Leaf)

Se pesan a sí mismos (son el final de la cadena).

Caja de Cocina

Compuesto (Composite)

Le pide el peso a cada “ElementoTransportable” que contiene y luego suma su peso.

Al tratar al Libro y a la Caja como un ElementoTransportable, puedes sumar el peso de la casa entera con una sola llamada, sin importar cuántas cajas anidadas haya.

🌲 2. Los 3 Pilares del Patrón Composite

El patrón de diseño Composite se basa en estos tres roles clave que trabajan juntos:

1. El Componente (El Contrato)

2. La Hoja (El Objeto Básico)

3. El Compuesto (El Contenedor)

🤔 1. ¿Qué pilar del Patrón Composite representa un objeto que NO puede tener hijos o elementos internos?

📁 3. El Ejemplo Clásico: Sistema de Archivos

El Patrón Composite es la base de cómo funcionan las estructuras de directorios en tu ordenador.

Estructura

Función (Ej. mostrar)

Elemento (Componente)

Define el método mostrarEstructura().

Archivo (Hoja)

Implementa mostrarEstructura() imprimiendo su propio nombre.

Carpeta (Compuesto)

Implementa mostrarEstructura() imprimiendo su nombre y llamando recursivamente a mostrarEstructura() en cada uno de sus contenidos.

El código que usa esta estructura solo tiene que llamar a CarpetaRaíz.mostrarEstructura() y el patrón se encarga de recorrer el árbol completo, sin saber cuántos niveles de anidación existen.

🤔 2. En el ejemplo de la Carpeta y el Archivo, ¿qué rol cumple el Componente que permite tratar a ambos por igual?

✅ 4. ¿Por Qué Usarlo?

El Composite te da dos beneficios principales:

  1. Uniformidad: Simplifica el código del cliente, ya que no tiene que distinguir entre elementos simples y complejos.
  2. Recursividad Natural: Permite estructuras jerárquicas con profundidad ilimitada, donde las operaciones (como calcular tamaño, mostrar, o buscar) se propagan de forma natural a través de la jerarquía.

❌ 5. Desventaja a Considerar

🤔 3. ¿Cuál es una desventaja notable del Patrón Composite que mencionamos?

💡 6. Conclusión

El Patrón Composite es esencial para modelar cualquier estructura de datos que se ramifica. Si tu problema implica árboles, listas, o jerarquías (como menús, interfaces gráficas o documentos XML), aplicar el Composite te garantizará un código limpio, extensible y elegante, donde la complejidad se maneja internamente en el objeto Compuesto, y la simplicidad reina en la interfaz.

🧠 7. Ejemplo Práctico en PHP

Vamos a implementar el patrón Composite con la analogía del sistema de archivos (📁 Carpetas y 📄 Archivos). El objetivo es poder recorrer toda la estructura con una sola llamada a mostrarEstructura().

<?php

// 🔹 1. El Componente (Interfaz común)
interface Elemento {
    public function mostrarEstructura(int $nivel = 0): void;
}

// 🔹 2. La Hoja (Archivo)
class Archivo implements Elemento {
    private string $nombre;

    public function __construct(string $nombre) {
        $this->nombre = $nombre;
    }

    public function mostrarEstructura(int $nivel = 0): void {
        echo str_repeat('  ', $nivel) . "📄 " . $this->nombre . PHP_EOL;
    }
}

// 🔹 3. El Compuesto (Carpeta)
class Carpeta implements Elemento {
    private string $nombre;
    /** @var Elemento[] */
    private array $elementos = [];

    public function __construct(string $nombre) {
        $this->nombre = $nombre;
    }

    public function agregar(Elemento $elemento): void {
        $this->elementos[] = $elemento;
    }

    public function mostrarEstructura(int $nivel = 0): void {
        echo str_repeat('  ', $nivel) . "📁 " . $this->nombre . PHP_EOL;

        foreach ($this->elementos as $elemento) {
            $elemento->mostrarEstructura($nivel + 1);
        }
    }
}

// 🔹 4. Uso del patrón
$documentos = new Carpeta('Documentos');
$imagenes = new Carpeta('Imágenes');

$documentos->agregar(new Archivo('curriculum.pdf'));
$documentos->agregar(new Archivo('contrato.docx'));

$imagenes->agregar(new Archivo('foto1.png'));
$imagenes->agregar(new Archivo('logo.svg'));

$root = new Carpeta('Carpeta Raíz');
$root->agregar($documentos);
$root->agregar($imagenes);

// 🔹 5. Ejecutar la operación común
$root->mostrarEstructura();

🖥️ Salida del programa:

📁 Carpeta Raíz
  📁 Documentos
    📄 curriculum.pdf
    📄 contrato.docx
  📁 Imágenes
    📄 foto1.png
    📄 logo.svg

EA, con esto nos despedimos, saluditos y nos vemos en los bares! 🍻