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 después trabajar con estas estructuras como si fueran objetos individuales. Es perfecto para representar jerarquías de partes y conjuntos en las que quieres tratar de manera uniforme los objetos individuales y los grupos de objetos.

Considera 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 los archivos como en las carpetas, y las carpetas deben sumar recursivamente su contenido. El patrón Composite hace que esto sea sencillo al proporcionar a las hojas (archivos) y 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 del cliente llama a getSize() sin preocuparse por si está trabajando con un solo archivo o con una estructura de carpetas profundamente anidada. El patrón gestiona la recursión internamente, lo que facilita trabajar con jerarquías complejas.

challenge icon

Desafío

Fácil

Construyamos un sistema de organigrama usando el Patrón Composite. Las empresas tienen una estructura jerárquica en la que los departamentos pueden contener empleados y otros subdepartamentos: una estructura de árbol perfecta para calcular los 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 permite tratar de la misma manera a los empleados individuales y a los departamentos completos al calcular los costos.
  • Employee.php: Incluye la interfaz OrganizationUnit y crea una clase Employee que la implemente. Un empleado es un nodo hoja en tu árbol organizativo. 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 haya 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 arreglo de empleados con sus nombres y salarios.

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

    Total Salary: [amount]

La ventaja del Patrón Composite es que llamar a getSalary() en el departamento Company calcula automáticamente la suma de todos los departamentos y empleados anidados: el código 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 department en los datos JSON
// Para cada department:
//   - Crea un nuevo objeto Department
//   - Añade cada employee a ese department
//   - Añade el department 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

Practica por tu cuenta: Compilador de PHP online