Menu
Coddy logo textTech

Patrón Composite

Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 80 de 91.

El Patrón Composite es un patrón de diseño estructural que te permite componer objetos en estructuras de árbol y luego trabajar con estas estructuras como si fueran objetos individuales. Es perfecto para representar jerarquías de parte-todo donde deseas tratar a los objetos individuales y a los grupos de objetos de manera uniforme.

Considere un sistema de archivos. Una carpeta puede contener archivos y otras carpetas.

Cuando calculas el tamaño total, quieres llamar al mismo método tanto en archivos como en carpetas, y las carpetas deben sumar recursivamente su contenido. El Patrón Composite hace que esto sea fluido al darles tanto a las hojas (archivos) como a los compuestos (carpetas) la misma interfaz.

<?php
interface FileSystemItem {
    public function getName(): string;
    public function getSize(): int;
}

class File implements FileSystemItem {
    public function __construct(
        private string $name,
        private int $size
    ) {}
    
    public function getName(): string {
        return $this->name;
    }
    
    public function getSize(): int {
        return $this->size;
    }
}

class Folder implements FileSystemItem {
    private array $items = [];
    
    public function __construct(private string $name) {}
    
    public function getName(): string {
        return $this->name;
    }
    
    public function add(FileSystemItem $item): void {
        $this->items[] = $item;
    }
    
    public function getSize(): int {
        $total = 0;
        foreach ($this->items as $item) {
            $total += $item->getSize();
        }
        return $total;
    }
}

Ahora puedes construir estructuras de árbol y tratarlas de manera uniforme:

<?php
$docs = new Folder("Documents");
$docs->add(new File("resume.pdf", 250));
$docs->add(new File("cover.docx", 50));

$images = new Folder("Images");
$images->add(new File("photo.jpg", 1500));

$root = new Folder("Root");
$root->add($docs);
$root->add($images);
$root->add(new File("readme.txt", 10));

echo $root->getSize();

Salida:

1810

El código cliente llama a getSize() sin preocuparse de si está tratando con un solo archivo o con una estructura de carpetas profundamente anidada. El patrón maneja la recursión internamente, facilitando el trabajo con jerarquías complejas.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de organigrama utilizando el Composite Pattern. Las empresas tienen una estructura jerárquica donde los departamentos pueden contener empleados y otros subdepartamentos — una estructura de árbol perfecta donde se desea calcular totales de manera uniforme en toda la organización.

Organizarás tu código en cuatro archivos:

  • OrganizationUnit.php — Define una interfaz OrganizationUnit que implementarán tanto los empleados individuales como los departamentos. Debe tener dos métodos: getName(): string y getSalary(): int. Esta interfaz común te permite tratar a los empleados individuales y a departamentos enteros de la misma manera al calcular costos.
  • Employee.php — Incluye la interfaz OrganizationUnit y crea una clase Employee que la implemente. Un empleado es un nodo hoja en tu árbol organizacional — tiene un nombre y un salario, pero no puede contener otras unidades. Usa la promoción de constructor para aceptar el nombre y el salario, e implementa ambos métodos de la interfaz.
  • Department.php — Incluye la interfaz OrganizationUnit y crea una clase Department que la implemente. Un departamento es un compuesto que puede contener tanto empleados como otros departamentos. Tu departamento debe:
    • Aceptar un nombre en su constructor
    • Implementar getName() para devolver el nombre del departamento
    • Tener un método add(OrganizationUnit $unit): void para añadir empleados o subdepartamentos
    • Implementar getSalary() para devolver el salario total de todas las unidades que contiene (sumando recursivamente todo lo que hay dentro)
  • main.php — Incluye los archivos Employee y Department. Recibirás una entrada: una cadena JSON que representa la estructura de la organización.

    El JSON tendrá este formato:

    {"Engineering": [{"name": "Alice", "salary": 80000}, {"name": "Bob", "salary": 75000}], "Sales": [{"name": "Carol", "salary": 65000}]}

    Cada clave es el nombre de un departamento, y su valor es un array de empleados con sus nombres y salarios.

    Crea un Department raíz llamado "Company". Para cada departamento en el JSON, crea un Department, añade sus empleados, luego añade ese departamento a la Company. Finalmente, imprime el salario total de la compañía en este formato:

    Total Salary: [amount]

La belleza del Composite Pattern es que llamar a getSalary() en el departamento Company calcula automáticamente la suma de todos los departamentos y empleados anidados — el código del cliente no necesita conocer la estructura interna.

Pruébalo tú mismo

<?php
require_once 'Employee.php';
require_once 'Department.php';

// Lee la entrada JSON
$input = trim(fgets(STDIN));
$data = (array)json_decode($input, true);

// TODO: Crea un Department raíz llamado "Company"

// TODO: Recorre cada departamento en los datos JSON
// Para cada departamento:
//   - Crea un nuevo objeto Department
//   - Agrega cada empleado a ese departamento
//   - Agrega el departamento a la Company

// TODO: Imprime el salario total en el formato: Total Salary: [amount]

?>
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos