Patrones de diseño en TypeScript: nivel avanzado con ejemplos
\n\nEl desarrollo de aplicaciones complejas en TypeScript requiere no solo conocimiento de sintaxis, sino también la capacidad de construir una arquitectura flexible y escalable. Los patrones de diseño GoF (Gang of Four) siguen siendo el estándar de oro, pero a nivel avanzado su aplicación se vuelve más sutil. En este artículo, analizaremos cuatro patrones potentes — Bridge, Visitor, State y Strategy — con ejemplos reales en TypeScript. Aprenderá a utilizar tipado estricto, genéricos e interfaces para implementar estos patrones.
\n\n1. Bridge: separamos la abstracción de la implementación
\n\nEl patrón Bridge (Puente) separa la abstracción y su implementación, permitiendo modificarlas de forma independiente. Esto es especialmente útil cuando tiene varias variaciones de funcionalidad que pueden combinarse.
\n\nEjemplo: Sistema de renderizado de figuras en diferentes APIs gráficas (Canvas y SVG).
\n\n// Implementación (Implementation)\ninterface Renderer {\n renderCircle(radius: number): void;\n renderSquare(side: number): void;\n}\n\nclass CanvasRenderer implements Renderer {\n renderCircle(radius: number): void {\n console.log(`Canvas: dibujamos círculo de radio ${radius}`);\n }\n renderSquare(side: number): void {\n console.log(`Canvas: dibujamos cuadrado de lado ${side}`);\n }\n}\n\nclass SVGRenderer implements Renderer {\n renderCircle(radius: number): void {\n console.log(`SVG: <circle r="${radius}" />`);\n }\n renderSquare(side: number): void {\n console.log(`SVG: <rect width="${side}" height="${side}" />`);\n }\n}\n\n// Abstracción (Abstraction)\nabstract class Shape {\n protected renderer: Renderer;\n\n constructor(renderer: Renderer) {\n this.renderer = renderer;\n }\n\n abstract draw(): void;\n}\n\nclass Circle extends Shape {\n private radius: number;\n\n constructor(renderer: Renderer, radius: number) {\n super(renderer);\n this.radius = radius;\n }\n\n draw(): void {\n this.renderer.renderCircle(this.radius);\n }\n}\n\nclass Square extends Shape {\n private side: number;\n\n constructor(renderer: Renderer, side: number) {\n super(renderer);\n this.side = side;\n }\n\n draw(): void {\n this.renderer.renderSquare(this.side);\n }\n}\n\n// Uso\nconst canvasCircle = new Circle(new CanvasRenderer(), 10);\ncanvasCircle.draw(); // Canvas: dibujamos círculo de radio 10\n\nconst svgSquare = new Square(new SVGRenderer(), 5);\nsvgSquare.draw(); // SVG: <rect width="5" height="5" />\n\nCaracterística clave: TypeScript garantiza que todas las implementaciones sigan el contrato Renderer. Agregar un nuevo tipo de figura o un nuevo renderizador no rompe el código existente.
2. Visitor: recorrido de estructuras complejas sin modificar clases
\n\nEl patrón Visitor (Visitante) permite agregar nuevas operaciones a objetos sin modificar sus clases. Es una solución ideal para trabajar con árboles, AST (árboles de sintaxis abstracta) o jerarquías de componentes.
\n\nEjemplo: Sistema de exportación de nodos de documento a diferentes formatos (JSON, XML).
\n\n// Elementos (Elements)\ninterface DocumentNode {\n accept(visitor: Visitor): void;\n}\n\nclass TextNode implements DocumentNode {\n constructor(public content: string) {}\n\n accept(visitor: Visitor): void {\n visitor.visitTextNode(this);\n }\n}\n\nclass ImageNode implements DocumentNode {\n constructor(public src: string, public alt: string) {}\n\n accept(visitor: Visitor): void {\n visitor.visitImageNode(this);\n }\n}\n\n// Visitante (Visitor)\ninterface Visitor {\n visitTextNode(node: TextNode): void;\n visitImageNode(node: ImageNode): void;\n}\n\nclass JSONExporter implements Visitor {\n private p