Polar Code 🎭

Command Palette

Search for a command to run...

04
Pièce N°04

CHAPITRE 3 : CLASSIFICATION DES DESIGN PATTERNS GoF

La lumière néon du bureau clignotait faiblement, donnant à l'écran une lueur de salle d'interrogatoire. J'avais aligné les principes. Maintenant, il fallait passer à l'arsenal. Le Gang of Four n'avait pas balancé ses patterns au hasard. Ils les avaient classés, rangés, étiquetés. Une typologie qui sentait le meurtre prémédité. C'est dans les tiroirs qu'on voit si un flic est organisé ou pas.

Les 3 familles

Trois catégories. Trois intentions criminelles.

1. Créationnels (Creational) Ils traitent de la naissance. Pas de l'acte d'amour, non. De l'instanciation. Comment les objets viennent au monde, qui les contrôle, qui les cache. C'est la famille qui s'occupe de remplacer l'opérateur new, ce témoin gênant qui lie tout à tout.

// Le problème : la création directe, trop intime.
const service = new ServiceConcret(); // Mariage forcé.
// Les patterns Créationnels viennent avec des solutions :
// - Factory Method : "Laisse-moi une méthode pour créer ce qu'il faut."
// - Abstract Factory : "J'ai besoin de familles entières d'objets liés."
// - Builder : "Un objet complexe, pièce par pièce, sans se perdre."
// - Prototype : "Clone-moi cet exemplaire, il est parfait."
// - Singleton : "Un et un seul. Comme le chef du syndicat."

2. Structurels (Structural) Ils s'occupent de l'assemblage. Comment les objets se composent pour former des structures plus grandes, plus flexibles, sans que tout ne s'effondre. C'est l'architecture des relations. Qui dépend de qui, qui décore qui, qui fait la façade.

// Le problème : des structures rigides, des héritages qui étouffent.
class PeripheriqueLourd extends MachineDeBase { /* ... */ }
// Les patterns Structurels proposent des ponts, des proxies, des décorateurs :
// - Adapter : "Fais rentrer ce vieux carré dans un trou rond."
// - Bridge : "Découple une abstraction de son implémentation, avant qu'ils ne se tuent."
// - Composite : "Traite un groupe d'objets comme un seul. L'unité dans la multitude."
// - Decorator : "Ajoute des responsabilités dynamiquement, sans hériter."
// - Facade : "Une interface simple pour un sous-système complexe."
// - Flyweight : "Partage pour économiser, quand les petits détails coûtent cher."
// - Proxy : "Un intermédiaire. Un garde du corps. Un filtre."

3. Comportementaux (Behavioral) Ceux-là gèrent les interactions et les responsabilités. Comment les objets communiquent, qui fait quoi, comment les algorithmes sont choisis. C'est la politique du système. La délégation, la chaîne de commandement, l'observation.

// Le problème : des comportements figés dans le béton de la classe.
if (type === 'A') { this.faireA(); } else if (type === 'B') { this.faireB(); } // L'enfer des conditions.
// Les patterns Comportementaux apportent la flexibilité, la négociation :
// - Chain of Responsibility : "Passe la requête dans la chaîne jusqu'à ce que quelqu'un la prenne."
// - Command : "Encapsule une requête comme un objet. Annulation, file d'attente."
// - Interpreter : "Pour un langage. Si vous devez l'utiliser, vous avez probablement un problème."
// - Iterator : "Parcours les éléments d'une collection sans en exposer les tripes."
// - Mediator : "Un centralisateur pour éviter que tous parlent à tous."
// - Memento : "Capture et restaure l'état d'un objet. L'oubli contrôlé."
// - Observer : "Abonne-toi à mes changements. Je te préviendrai."
// - State : "Change de comportement quand ton état change."
// - Strategy : "Définit une famille d'algorithmes, rend-les interchangeables."
// - Template Method : "Définit le squelette d'un algorithme, laisse les sous-classes remplir les trous."
// - Visitor : "Sépare l'algorithme de la structure d'objet qu'il manipule."

Portée

Le Gang a aussi coupé selon une autre ligne : la portée.

Portée Classe Ces patterns traitent des relations entre classes. Ils se jouent à la compilation, par l'héritage. C'est statique, lié par le sang.

  • Factory Method, Template Method, Interpreter (et quelques autres selon l'interprétation).
  • On les reconnaît : ils utilisent l'héritage pour étendre le comportement.

Portée Objet Ces patterns traitent des relations entre objets. Ils se jouent à l'exécution, par la composition. C'est dynamique, lié par le contrat.

  • La grande majorité des patterns (Observer, Strategy, Decorator...).
  • On les reconnaît : ils définissent des interfaces et composent des objets pour changer le comportement.
// Portée CLASSE (via héritage)
abstract class Createur {
    // Factory Method : la création est déléguée à une sous-classe.
    abstract fabriquerProduit(): Produit;

    operation() {
        const produit = this.fabriquerProduit(); // Appel polymorphique
        return produit.operation();
    }
}
// La relation Createur <-> ProduitConcret est fixée à la compilation.

// Portée OBJET (via composition)
class Contexte {
    // Strategy : l'algorithme est injecté, composé.
    constructor(private strategie: Strategie) {}

    setStrategie(s: Strategie) { this.strategie = s; } // Changement à la volée.

    executer() {
        return this.strategie.executerAlgorithme(); // Délégation.
    }
}
// La relation Contexte <-> Strategie est dynamique, à l'exécution.

Pourquoi cette classification existe

Pour la même raison qu'on classe les crimes. Pour s'y retrouver. Pour savoir quel outil sortir face à quel problème.

  1. L'intention première (Création, Structure, Comportement) : Tu as un problème de création ? Va voir dans la première famille. Un problème de communication ? C'est la troisième. C'est le premier filtre, celui qui évite de se perdre.
  2. Le niveau d'impact (Classe vs Objet) : Tu veux une solution liée à la structure hiérarchique de ton code (héritage), ou une solution plus souple, basée sur la composition d'objets ? C'est le second filtre.

Cette taxonomie, c'est une grille de lecture. Une carte pour le territoire chaotique des problèmes de conception. Sans elle, les 23 patterns ne seraient qu'une liste à la Prévert, une recette de cuisine sans index.

Limites de la classification

Mais comme toute classification, elle a ses angles morts. Ses cadavres dans le placard.

  1. Les hybrides : Certains patterns glissent entre les cases. Le Bridge est-il vraiment juste "Structurel" ? Il a un fort aspect "Comportemental" en découplant abstraction et implémentation. Le Visitor est "Comportemental", mais il impacte profondément la structure des classes qu'il visite. Les frontières sont poreuses.
  2. Une vision statique : Cette classification de 1994 capture une certaine vision, principalement statique et orientée objet classique. Elle peine à intégrer élégamment des paradigmes plus modernes comme la programmation fonctionnelle, les flux réactifs, ou les microservices.
  3. L'omission du "Pourquoi" profond : Elle classe le "Quoi" (l'intention technique), mais parfois masque le "Pourquoi" métier ou humain derrière l'usage d'un pattern. On choisit un Singleton pour le contrôle, mais aussi parfois par paresse, par méconnaissance d'alternatives (Dependency Injection).
  4. Une fausse exhaustivité : Elle peut laisser croire que les 23 patterns GoF sont l'alpha et l'oméga. Ils ne le sont pas. D'autres patterns existent (Architecturaux, de Concurrence, Spécifiques aux langages). Et surtout, le plus important n'est pas dans la liste : savoir quand ne pas les utiliser.

La classification du Gang est une lampe torpe puissante. Elle éclaire magistralement le cœur des problèmes OO classiques. Mais il ne faut jamais oublier que la carte n'est pas le territoire. Utiliser un pattern, c'est d'abord comprendre la force qui l'a créé : un problème récurrent, qui suinte la dette technique et la rigidité. La classification n'est que le tiroir où ranger l'outil. L'important, c'est la main qui le saisit, et la tête qui sait pourquoi.

Je fermai l'onglet du navigateur où s'alignaient les 23 noms. La classification était claire. Presque trop. Dans la vraie vie, les problèmes sont sales, mélangés. On ne choisit pas un pattern parce qu'il est dans la bonne famille. On le choisit parce qu'il sent la même pourriture que le problème qu'on a sous les yeux.

La prochaine étape serait de plonger dans le premier tiroir. Le plus fondamental. Le plus lourd de conséquences. La famille Créationnelle.

Mais pour l'instant, la classification restait là, comme une grille d'identification en commissariat. Utile. Nécessaire. Et profondément incomplète.