Modèles de Conception en TypeScript : Niveau Avancé avec Exemples
\n\nDévelopper des applications complexes en TypeScript nécessite non seulement une connaissance de la syntaxe, mais aussi la capacité de construire une architecture flexible et évolutive. Les modèles de conception GoF (Gang of Four) restent la référence, mais à un niveau avancé, leur application devient plus nuancée. Dans cet article, nous analyserons quatre modèles puissants — Pont, Visiteur, État et Stratégie — avec des exemples concrets en TypeScript. Vous apprendrez à utiliser le typage fort, les génériques et les interfaces pour implémenter ces modèles.
\n\n1. Pont : Séparer l’Abstraction de l’Implémentation
\n\nLe modèle Pont sépare une abstraction de son implémentation, permettant aux deux de varier indépendamment. Ceci est particulièrement utile lorsque vous avez plusieurs variations de fonctionnalités qui peuvent être combinées.
\n\nExemple : Un système de rendu de formes utilisant différentes API graphiques (Canvas et SVG).
\n\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: drawing a circle with radius ${radius}`);\n }\n renderSquare(side: number): void {\n console.log(`Canvas: drawing a square with side ${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// 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// Usage\nconst canvasCircle = new Circle(new CanvasRenderer(), 10);\ncanvasCircle.draw(); // Canvas: drawing a circle with radius 10\n\nconst svgSquare = new Square(new SVGRenderer(), 5);\nsvgSquare.draw(); // SVG: <rect width="5" height="5" />\n\nCaractéristique Clé : TypeScript garantit que toutes les implémentations suivent le contrat Renderer. Ajouter un nouveau type de forme ou un nouveau moteur de rendu ne casse pas le code existant.
2. Visiteur : Parcourir des Structures Complexes Sans Modifier les Classes
\n\nLe modèle Visiteur permet d’ajouter de nouvelles opérations aux objets sans modifier leurs classes. C’est une solution idéale pour travailler avec des arbres, des AST (arbres syntaxiques abstraits) ou des hiérarchies de composants.
\n\nExemple : Un système d’exportation de nœuds de document vers différents formats (JSON, XML).
\n\n// 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// Visitor\ninterface Visitor {\n visitTextNode(node: TextNode): void;\n visitImageNode(node: ImageNode): void;\n}\n\nclass JSONExporter implements Visitor {\n private p