Patrons de conception en JavaScript : niveau avancé avec exemples sur Node.js
Les patrons de conception sont des solutions architecturales éprouvées pour des problèmes typiques. Si les patrons de base (Singleton, Fabrique, Observateur) vous sont déjà familiers, il est temps d'approfondir des constructions plus complexes. Dans cet article, nous allons analyser quatre patrons GoF avancés avec des exemples en JavaScript (Node.js) : Composite, Chaîne de responsabilité, État et Mémento. Ces patrons vous aideront à écrire un code flexible, évolutif et maintenable.
1. Composite
Objectif : Permet de regrouper des objets dans une structure arborescente et de travailler avec chaque objet ou groupe de manière uniforme.
Exemple : Système de fichiers où un dossier peut contenir des fichiers et d'autres dossiers. Nous voulons calculer la taille totale.
// Composantclass FileSystemComponent { getSize() { throw new Error('La méthode getSize() doit être implémentée'); }}
// Feuilleclass File extends FileSystemComponent { constructor(name, size) { super(); this.name = name; this.size = size; }
getSize() { return this.size; }}
// Conteneur (nœud)class Folder extends FileSystemComponent { constructor(name) { super(); this.name = name; this.children = []; }
add(component) { this.children.push(component); }
getSize() { return this.children.reduce((total, child) => total + child.getSize(), 0); }}
// Utilisationconst root = new Folder('root');const src = new Folder('src');const index = new File('index.js', 500);const utils = new File('utils.js', 300);
src.add(index);src.add(utils);root.add(src);root.add(new File('package.json', 200));
console.log(`Taille totale : ${root.getSize()} octets`); // 1000 octetsAvantages : Simplifie le travail avec les arbres, masque la complexité de la hiérarchie au client.
2. Chaîne de responsabilité
Objectif : Permet de transmettre une requête le long d'une chaîne de gestionnaires jusqu'à ce que l'un d'eux la traite.
Exemple : Traitement des requêtes HTTP dans Express.js (middleware).
class Handler { setNext(handler) { this.next = handler; return handler; }
handle(request) { if (this.next) { return this.next.handle(request); } return null; }}
class AuthHandler extends Handler { handle(request) { if (!request.token) { return 'Erreur : non autorisé'; } console.log('AuthHandler : vérification réussie'); return super.handle(request); }}
class RoleHandler extends Handler { handle(request) { if (request.role !== 'admin') { return 'Erreur : droits insuffisants'; } console.log('RoleHandler : rôle confirmé'); return super.handle(request); }}
class LoggingHandler extends Handler { handle(request) { console.log(`LoggingHandler : requête de ${request.user}`); return super.handle(request); }}
// Construction de la chaîneconst auth = new AuthHandler();const role = new RoleHandler();const log = new LoggingHandler();auth.setNext(role).setNext(log);
const request = { token: 'abc123', role: 'admin', user: 'Ivan' };const result = auth.handle(request);console.log(result); // null (tout va bien)
const badRequest = { token: 'abc123', role: 'user', user: 'Petr' };console.log(auth.handle(badRequest)); // 'Erreur : droits insuffisants'Avantages : Réduit le couplage, facilite l'ajout/suppression de gestionnaires.
3. État
Objectif : Permet à un objet de modifier son comportement en fonction de son état interne.
Exemple : Document avec les états : Brouillon, En modération, Publié.
class Docu