Choisir le bon pattern
Partir du problème, pas du pattern
Le problème
Connaître les patterns individuellement ne suffit pas. La vraie compétence, c'est de regarder du code et de savoir lequel appliquer, ou de reconnaître qu'aucun ne s'impose.
La mauvaise approche : "j'ai appris Factory aujourd'hui, je vais le mettre quelque part". Le pattern devient une solution qui cherche un problème.
La bonne approche : partir de la douleur dans le code.
Partir du symptôme
| Tu observes ça dans le code | Tu penses à ça |
|---|---|
| La même valeur hardcodée à 5 endroits | Singleton, centraliser la config |
new MonObjet() dupliqué partout avec de la logique dedans | Factory, encapsuler la création |
| Le composant parle directement à une API externe | Adapter, abstraire la source de données |
| Ajouter une feature oblige à modifier une classe existante | Decorator, enrichir sans toucher |
Des if/else sur un comportement qui change selon le contexte | Strategy, extraire l'algorithme |
| Un composant doit "réagir" à des changements sans être couplé à la source | Observer, notifier sans dépendance directe |
| Des actions qui devraient être réversibles ne le sont pas | Command, encapsuler l'action et son inverse |
Questions à se poser
Le problème concerne la création d'objets ? → Singleton, Factory, Builder
Le problème concerne la structure, comment les objets sont composés ? → Adapter, Decorator, Facade, Proxy
Le problème concerne la communication entre objets ? → Observer, Strategy, Command
Ce que les patterns ne sont pas
Les patterns GoF ne couvrent pas tout. Beaucoup de problèmes en front-end se résolvent autrement :
- Un composant trop gros → découpage en composants, pas nécessairement un pattern GoF
- De la duplication de logique → un hook custom ou une fonction utilitaire
- De la prop drilling → Context API ou un store (qui est lui-même un Observer, mais idiomatique React)
Plaquer un pattern GoF sur un problème React standard, c'est souvent de la surconception.
La règle d'or
Un pattern se justifie quand il supprime une douleur concrète. Si tu n'arrives pas à expliquer en une phrase le problème qu'il résout dans ton code, c'est qu'il n'a probablement pas sa place.
// ✗ Factory sans raison
class UserFactory {
static create(name: string) {
return { name }; // juste un objet littéral déguisé
}
}
// ✓ Factory justifiée, la création est complexe et réutilisée
class PokemonFactory {
static create(raw: any): Pokemon {
return {
id: raw.id,
name: raw.name,
sprite: raw.sprites.front_default,
types: raw.types.map((t: any) => t.type.name),
stats: {
hp: raw.stats[0].base_stat,
attack: raw.stats[1].base_stat,
defense: raw.stats[2].base_stat,
speed: raw.stats[5].base_stat,
},
};
}
}La différence : dans le deuxième cas, sans Factory, cette logique serait dupliquée et couplée au composant qui fait le fetch.