Patrón Composite: Estructuras Jerárquicas Uniformes
design-patternsstructuralcomposite

Intención
Composite permite tratar objetos individuales y composiciones de objetos de manera uniforme. Compone objetos en estructuras de árbol para representar jerarquías parte-todo.
El Problema
Sin Composite, el código cliente necesita distinguir entre objetos simples y compuestos:
// Código cliente complejo
function calculatePrice(item: unknown): number {
if (item instanceof Product) {
return item.price;
} else if (item instanceof Box) {
let total = 0;
for (const child of item.children) {
total += calculatePrice(child); // Recursión manual
}
return total;
}
throw new Error('Unknown item type');
}La Solución: Composite
classDiagram
class Component {
<<interface>>
+operation(): number
+add(child: Component)
+remove(child: Component)
}
class Leaf {
+operation(): number
}
class Composite {
-children: Component[]
+operation(): number
+add(child: Component)
+remove(child: Component)
}
Component <|.. Leaf
Component <|.. Composite
Composite o--> ComponentImplementación TypeScript
// Componente base
interface FileSystemNode {
getName(): string;
getSize(): number;
print(indent?: string): void;
}
// Hoja: Archivo
class File implements FileSystemNode {
constructor(
private name: string,
private size: number
) {}
getName(): string {
return this.name;
}
getSize(): number {
return this.size;
}
print(indent = ''): void {
console.log(`${indent}📄 ${this.name} (${this.size} bytes)`);
}
}
// Composite: Directorio
class Directory implements FileSystemNode {
private children: FileSystemNode[] = [];
constructor(private name: string) {}
getName(): string {
return this.name;
}
getSize(): number {
return this.children.reduce((sum, child) => sum + child.getSize(), 0);
}
add(node: FileSystemNode): this {
this.children.push(node);
return this;
}
print(indent = ''): void {
console.log(`${indent}📁 ${this.name}/`);
for (const child of this.children) {
child.print(indent + ' ');
}
}
}
// Uso - El cliente trata todo uniformemente
const root = new Directory('project')
.add(new File('package.json', 1024))
.add(new File('README.md', 2048))
.add(
new Directory('src')
.add(new File('index.ts', 512))
.add(new File('utils.ts', 256))
);
// Operación uniforme en toda la jerarquía
console.log(`Total: ${root.getSize()} bytes`);
root.print();Cuándo Usar
| Situación | Recomendación |
|---|---|
| Estructuras de árbol (DOM, FS) | ✅ Recomendado |
| Menús con submenús | ✅ Recomendado |
| Expresiones aritméticas | ✅ Recomendado |
| Estructuras planas sin jerarquía | ❌ Innecesario |
Conclusión
Composite simplifica el código cliente al permitir tratar elementos individuales y grupos de la misma manera.