Primero, definimos una interfaz común que será implementada por tanto los componentes hoja como los compuestos.
// IComponent.ts
export interface IComponent {
operation(): string;
}
Los componentes hoja son los objetos finales de la jerarquía que no tienen hijos.
// Leaf.ts
import { IComponent } from './IComponent';
export class Leaf implements IComponent {
private name: string;
constructor(name: string) {
this.name = name;
}
operation(): string {
return `Leaf ${this.name} operation`;
}
}
Los componentes compuestos pueden tener hijos que son tanto hojas como otros compuestos. Implementan la interfaz común y gestionan sus hijos.
// Composite.ts
import { IComponent } from './IComponent';
export class Composite implements IComponent {
private children: IComponent[] = [];
add(component: IComponent): void {
this.children.push(component);
}
remove(component: IComponent): void {
const index = this.children.indexOf(component);
if (index !== -1) {
this.children.splice(index, 1);
}
}
operation(): string {
const results: string[] = [];
for (const child of this.children) {
results.push(child.operation());
}
return `Composite operation with [${results.join(', ')}]`;
}
}
Vamos a ensamblar todo y ver cómo funciona en un ejemplo práctico.
// main.ts
import { Leaf } from './Leaf';
import { Composite } from './Composite';
const leaf1 = new Leaf('A');
const leaf2 = new Leaf('B');
const leaf3 = new Leaf('C');
const composite1 = new Composite();
composite1.add(leaf1);
composite1.add(leaf2);
const composite2 = new Composite();
composite2.add(composite1);
composite2.add(leaf3);
console.log(composite2.operation());
1. Crear Hojas: Creamos tres hojas leaf1
, leaf2
, y leaf3
.
2. Crear Compuestos: Creamos dos compuestos composite1
y composite2
.
3. Agregar Hojas a Compuestos: Agregamos leaf1
y leaf2
a composite1
.
4. Componer Compuestos: Agregamos composite1
y leaf3
a composite2
.
5. Ejecutar Operación: Llamamos al método
de operation
composite2
, que a su vez llama a los métodos operation de sus hijos, demostrando la composición jerárquica.
La salida esperada de este programa es:
Composite operation with [Composite operation with [Leaf A operation, Leaf B operation], Leaf C operation]
El patrón Composite permite construir estructuras de objetos en forma de árbol y trabajar con ellas de manera uniforme. En este tutorial, implementamos el patrón Composite en TypeScript, creando una jerarquía de objetos que pueden ser tratados de la misma manera, ya sean simples (hojas) o compuestos (nodos).
Este patrón es útil en situaciones donde se necesita tratar un grupo de objetos de manera similar a un objeto individual, simplificando la gestión y el uso de estructuras complejas.
Para mayor claridad, aquí está el código completo organizado en archivos:
IComponent.ts
export interface IComponent {
operation(): string;
}
Leaf.ts
import { IComponent } from './IComponent';
export class Leaf implements IComponent {
private name: string;
constructor(name: string) {
this.name = name;
}
operation(): string {
return `Leaf ${this.name} operation`;
}
}
Composite.ts
import { IComponent } from './IComponent';
export class Composite implements IComponent {
private children: IComponent[] = [];
add(component: IComponent): void {
this.children.push(component);
}
remove(component: IComponent): void {
const index = this.children.indexOf(component);
if (index !== -1) {
this.children.splice(index, 1);
}
}
operation(): string {
const results: string[] = [];
for (const child of this.children) {
results.push(child.operation());
}
return `Composite operation with [${results.join(', ')}]`;
}
}
main.ts
import { Leaf } from './Leaf';
import { Composite } from './Composite';
const leaf1 = new Leaf('A');
const leaf2 = new Leaf('B');
const leaf3 = new Leaf('C');
const composite1 = new Composite();
composite1.add(leaf1);
composite1.add(leaf2);
const composite2 = new Composite();
composite2.add(composite1);
composite2.add(leaf3);
console.log(composite2.operation());
Este tutorial cubre todos los aspectos necesarios para implementar y entender el patrón Composite en TypeScript. ¡Espero que lo encuentres útil!
Jorge García
Fullstack developer