Padrões de Projeto em TypeScript: nível avançado com exemplos
\n\nO desenvolvimento de aplicações complexas em TypeScript exige não apenas conhecimento de sintaxe, mas também a capacidade de construir uma arquitetura flexível e escalável. Os padrões de projeto GoF (Gang of Four) continuam sendo o padrão ouro, mas em nível avançado sua aplicação se torna mais sutil. Neste artigo, analisaremos quatro padrões poderosos — Bridge, Visitor, State e Strategy — com exemplos reais em TypeScript. Você aprenderá como usar tipagem forte, genéricos e interfaces para implementar esses padrões.
\n\n1. Bridge: separando abstração da implementação
\n\nO padrão Bridge (Ponte) separa a abstração e sua implementação, permitindo que sejam alteradas independentemente. Isso é especialmente útil quando você tem várias variações de funcionalidade que podem ser combinadas.
\n\nExemplo: Sistema de renderização de formas em diferentes APIs gráficas (Canvas e SVG).
\n\n// Implementação (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: desenhando círculo com raio ${radius}`);\n }\n renderSquare(side: number): void {\n console.log(`Canvas: desenhando quadrado com 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// Abstração (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: desenhando círculo com raio 10\n\nconst svgSquare = new Square(new SVGRenderer(), 5);\nsvgSquare.draw(); // SVG: <rect width="5" height="5" />\n\nCaracterística chave: TypeScript garante que todas as implementações sigam o contrato Renderer. Adicionar um novo tipo de forma ou um novo renderizador não quebra o código existente.
2. Visitor: percorrendo estruturas complexas sem alterar classes
\n\nO padrão Visitor (Visitante) permite adicionar novas operações a objetos sem alterar suas classes. É uma solução ideal para trabalhar com árvores, AST (árvores sintáticas abstratas) ou hierarquias de componentes.
\n\nExemplo: Sistema de exportação de nós de documento para 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