Menu
Coddy logo textTech

Patrón Composite

Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy. Lección 75 de 87.

El patrón Composite es un patrón de diseño estructural que te permite componer objetos en estructuras de árbol para representar jerarquías de partes y conjuntos. Permite a los clientes tratar de manera uniforme los objetos individuales y las composiciones de objetos mediante una interfaz común.

Piensa en un sistema de archivos: una carpeta puede contener archivos y otras carpetas, que pueden contener más archivos y carpetas. Tanto si trabajas con un solo archivo como con toda una estructura de carpetas, quieres realizar operaciones como «obtener tamaño» de la misma manera. El patrón define una interfaz Component, objetos Leaf (elementos individuales) y objetos Composite (contenedores que contienen elementos secundarios):

interface FileComponent {
    void display(String indent);
    int getSize();
}

class File implements FileComponent {
    private String name;
    private int size;
    
    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }
    
    public void display(String indent) {
        System.out.println(indent + name + " (" + size + "KB)");
    }
    
    public int getSize() {
        return size;
    }
}

class Folder implements FileComponent {
    private String name;
    private List<FileComponent> children = new ArrayList<>();
    
    public Folder(String name) {
        this.name = name;
    }
    
    public void add(FileComponent component) {
        children.add(component);
    }
    
    public void display(String indent) {
        System.out.println(indent + name + "/");
        for (FileComponent child : children) {
            child.display(indent + "  ");
        }
    }
    
    public int getSize() {
        return children.stream().mapToInt(FileComponent::getSize).sum();
    }
}

El compuesto delega las operaciones a sus hijos, lo que permite estructuras recursivas. Los clientes interactúan con el árbol sin saber si están trabajando con una hoja o con un compuesto:

Folder root = new Folder("Documents");
root.add(new File("resume.pdf", 150));

Folder photos = new Folder("Photos");
photos.add(new File("vacation.jpg", 2000));
root.add(photos);

root.display("");
System.out.println("Total: " + root.getSize() + "KB");

El patrón Composite es ideal para representar jerarquías como organigramas, componentes de interfaz de usuario o sistemas de menús en los que necesitas tratar los grupos y los elementos individuales de la misma manera.

challenge icon

Desafío

Fácil

¡Construyamos un sistema de organigrama utilizando el patrón Composite! Crearás una estructura en la que los departamentos pueden contener empleados y otros subdepartamentos, lo que permitirá calcular los salarios totales y mostrar la jerarquía de manera uniforme, tanto si observas a un solo empleado como a toda una división.

Organizarás tu código en cuatro archivos:

  • OrganizationComponent.java: Define la interfaz del componente que implementarán tanto los empleados como los departamentos. Debe declarar dos métodos: showDetails(String indent) para mostrar el componente con la indentación adecuada, y getSalary(), que devuelve el salario total como un entero.
  • Employee.java: Crea la clase hoja que representa a los trabajadores individuales. Un Employee tiene un nombre (String) y un salario (int), ambos establecidos mediante el constructor. Cuando se llama a showDetails, debe imprimir [indent][name]: $[salary]. El método getSalary simplemente devuelve el salario del empleado.
  • Department.java: Crea la clase compuesta que puede contener tanto empleados como subdepartamentos. Un Department tiene un nombre (String) y mantiene una lista de elementos secundarios OrganizationComponent. Debe tener un método add(OrganizationComponent component) para añadir miembros. Cuando se llama a showDetails, imprime [indent][name] Department y después llama a showDetails en cada elemento secundario con una indentación mayor (añade dos espacios). El método getSalary devuelve la suma de los salarios de todos los elementos secundarios.
  • Main.java: ¡Construye tu organización! Recibirás cuatro entradas: dos nombres de empleados con sus salarios, y el nombre de un subdepartamento con un empleado.

    Crea un departamento "Engineering" como raíz. Añade dos empleados usando los dos primeros pares de nombre/salario. Después, crea un subdepartamento usando la tercera entrada, añade un empleado usando el cuarto par de nombre/salario y añade este subdepartamento a Engineering.

    Llama a showDetails("") en el departamento Engineering y después imprime el salario total con el formato Total Salary: $[amount].

Recibirás las entradas en este orden: nombre de employee1 (String), salario de employee1 (int), nombre de employee2 (String), salario de employee2 (int), nombre del subdepartamento (String), nombre de employee3 (String), salario de employee3 (int).

Por ejemplo, con las entradas Alice, 75000, Bob, 65000, QA, Charlie, 55000, tu salida sería:

Engineering Department
  Alice: $75000
  Bob: $65000
  QA Department
    Charlie: $55000
Total Salary: $195000

Observa cómo los mismos métodos showDetails y getSalary funcionan perfectamente tanto cuando se llaman en un solo empleado como cuando se llaman en un departamento completo que contiene subdepartamentos anidados. La estructura compuesta gestiona la recursión automáticamente, ¡lo que te permite tratar toda la jerarquía de manera uniforme!

Pruébalo tú mismo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Leer entradas
        String emp1Name = scanner.nextLine();
        int emp1Salary = Integer.parseInt(scanner.nextLine());
        String emp2Name = scanner.nextLine();
        int emp2Salary = Integer.parseInt(scanner.nextLine());
        String subDeptName = scanner.nextLine();
        String emp3Name = scanner.nextLine();
        int emp3Salary = Integer.parseInt(scanner.nextLine());
        
        // TODO: Create the "Engineering" department as the root
        
        // TODO: Crea y añade dos empleados a Engineering usando los datos de emp1 y emp2
        
        // TODO: Crea un subdepartamento usando subDeptName
        
        // TODO: Crea y añade un empleado al subdepartamento usando los datos de emp3
        
        // TODO: Añade el subdepartamento a Engineering
        
        // TODO: Call showDetails("") on the Engineering department
        
        // 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 Java online