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.
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, ygetSalary(), que devuelve el salario total como un entero.Employee.java: Crea la clase hoja que representa a los trabajadores individuales. UnEmployeetiene un nombre (String) y un salario (int), ambos establecidos mediante el constructor. Cuando se llama ashowDetails, debe imprimir[indent][name]: $[salary]. El métodogetSalarysimplemente devuelve el salario del empleado.Department.java: Crea la clase compuesta que puede contener tanto empleados como subdepartamentos. UnDepartmenttiene un nombre (String) y mantiene una lista de elementos secundariosOrganizationComponent. Debe tener un métodoadd(OrganizationComponent component)para añadir miembros. Cuando se llama ashowDetails, imprime[indent][name] Departmenty después llama ashowDetailsen cada elemento secundario con una indentación mayor (añade dos espacios). El métodogetSalarydevuelve 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 formatoTotal 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: $195000Observa 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]
}
}
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
1Fundamentos de OOP
Archivos externosIntroducción a la OOPClases vs. ObjetosLa palabra clave thisMétodosCampos (Atributos)Método constructorSobrecarga de constructoresResumen - Calculadora simple4Herencia
Herencia básica (extends)La palabra clave superSobrescritura de métodos (@Override)Encadenamiento de constructoresLa clase ObjectHerencia simple y multinivelPor qué no hay herencia múltiple de clasesResumen - Jerarquía de empleados7Métodos especiales y la clase Object
Método toString()equals() y hashCode()Método clone()compareTo() y ComparableInterfaz ComparatorResumen - Ordenamiento personalizado2Modificadores de acceso y encapsulamiento
Visión general de los niveles de accesoMétodos Getter y SetterOcultamiento de informaciónLa palabra clave finalResumen - Gestor de cuentas bancarias5Polimorfismo
Fundamentos de sobrecarga de métodosSobrescritura de métodos (tiempo de ejecución)Upcasting y DowncastingEl operador instanceofClases y métodos abstractosResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaAgregación vs. ComposiciónClases internas, anidadas y anónimasEnums y métodos de EnumRecords (Java 16+)Clases selladas (Java 17+)11Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón BuilderPatrón ObserverPatrón Strategy3Propiedades de clase y miembros estáticos
Variables de instancia vs. estáticasMétodos estáticosBloques estáticosConstantes (static final)Repaso - Contador y utilidad6Interfaces y Clases Abstractas
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesMétodos Default y Static en InterfacesClases Abstractas vs InterfacesInterfaces FuncionalesResumen - Sistema de Pagos9Genéricos
Introducción a los genéricosClases genéricasMétodos genéricosParámetros de tipo delimitadosComodines (?, extends, super)Resumen - Contenedor genérico12Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón IteratorPractica por tu cuenta: Compilador de Java online