Modèles de conception en JavaScript avec exemples de code

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Patrons de conception en JavaScript avec exemples



Les patrons de conception (design patterns) sont des solutions éprouvées pour des problèmes courants dans le développement de logiciels. Pour un développeur JavaScript, la connaissance des patrons est particulièrement importante, car le langage possède un modèle objet flexible et est largement utilisé à la fois côté client et côté serveur (Node.js). Dans cet article, nous allons analyser quatre patrons clés avec des exemples pratiques en JavaScript.



Pourquoi étudier les patrons de conception ?

Les patrons aident à :

  • Simplifier la maintenance et l'évolutivité du code
  • Rendre le code plus lisible et prévisible
  • Éviter de "réinventer la roue"
  • Améliorer la communication au sein de l'équipe (langage commun)


1. Singleton

Le patron Singleton garantit qu'une classe n'a qu'une seule instance et fournit un point d'accès global à celle-ci. Dans Node.js, ce patron est souvent utilisé pour la connexion à une base de données, la gestion de la configuration ou la journalisation.



class DatabaseConnection {  constructor() {    if (DatabaseConnection.instance) {      return DatabaseConnection.instance;    }    this.connection = null;    DatabaseConnection.instance = this;  }

connect() { // Simulation de connexion à la BD this.connection = "connected"; console.log("Connexion à la BD établie"); }

query(sql) { if (!this.connection) { throw new Error("Pas de connexion à la BD"); } console.log(`Exécution de la requête : ${sql}`); return { data: [] }; }}

// Utilisationconst db1 = new DatabaseConnection();const db2 = new DatabaseConnection();

db1.connect();console.log(db1 === db2); // true - les deux pointent vers la même instancedb2.query("SELECT * FROM users");


Quand l'utiliser : gestion de ressources partagées (BD, configuration, cache). Attention : une utilisation excessive peut entraîner un fort couplage du code.



2. Factory (Fabrique)

Factory Method définit une interface pour créer un objet, mais permet aux sous-classes de modifier le type d'objet créé. En JavaScript, cela est souvent implémenté via des fonctions ou des classes ordinaires.



class User {  constructor(name, role) {    this.name = name;    this.role = role;  }

getPermissions() { return []; }}

class Admin extends User { getPermissions() { return ["read", "write", "delete", "manage"]; }}

class Editor extends User { getPermissions() { return ["read", "write"]; }}

class Viewer extends User { getPermissions() { return ["read"]; }}

// Fabriqueclass UserFactory { createUser(name, role) { switch (role) { case "admin": return new Admin(name, role); case "editor": return new Editor(name, role); case "viewer": return new Viewer(name, role); default: throw new Error("Rôle inconnu"); } }}

// Utilisationconst factory = new UserFactory();const admin = factory.createUser("Anna", "admin");const viewer = factory.createUser("Ivan", "viewer");

console.log(admin.getPermissions()); // ["read", "write", "delete", "manage"]console.log(viewer.getPermissions()); // ["read"]


Avantages : gestion centralisée de la création d'objets, facilité d'ajout de nouveaux types, dissimulation de la logique d'instanciation.



3. Observer (Observateur)

Le patron Observer définit une dépendance "un à plusieurs" entre les objets. Lorsqu'un objet (sujet) change d'état, tous les objets dépendants (observateurs) sont automatiquement notifiés. C'est la base de la programmation événementielle dans Node.js.



class EventEmitter {  constructor() {    this.events = {};  }

on(eventName, listener) { if (!this.events[eventName]) { this.events[eventName] = []; } this.events[eventName].push(listener); }

emit(eventName, data) { const listeners = this.events[eventName]; if (listeners) { listeners.forEach(listener => listener(data)); } }

off(eventName, listenerToRemove) { const listeners = this.events[eventName]; if (listeners) { this.events[eventName] = listeners.filter( listener => listener !== listenerToRemove ); } }}

// Utilisationconst emitter = new EventEmitter();

function onUserLoggedIn(user) { console.log(`Utilisateur connecté : ${user.name}`);}

emitter.on("userLoggedIn", onUserLoggedIn);

emitter.emit("userLoggedIn", { name: "Anna" });// Utilisateur connecté : Anna

emitter.off("userLoggedIn", onUserLoggedIn);

emitter.emit("userLoggedIn", { name: "Ivan" });// Rien ne se passe, l'observateur a été retiré


Quand l'utiliser : systèmes d'événements, mises à jour d'interface utilisateur, notifications, architecture MVC. Attention : peut entraîner des fuites mémoire si les observateurs ne sont pas correctement supprimés.



4. Module

Le patron Module permet d'encapsuler des données et des méthodes privées, en n'exposant qu'une interface publique. En JavaScript moderne, cela est réalisé via les modules ES (import/export) ou en utilisant des fermetures (closures).



// Compteur de module utilisant une fermetureconst CounterModule = (function() {  let count = 0; // variable privée

function validateValue(value) { return typeof value === 'number' && !isNaN(value); }

return { increment() { count++; return count; }, decrement() { count--; return count; }, getCount() { return count; }, setCount(value) { if (validateValue(value)) { count = value; } else { console.error("Valeur invalide"); } } };})();

// Utilisationconsole.log(CounterModule.getCount()); // 0CounterModule.increment();CounterModule.increment();console.log(CounterModule.getCount()); // 2CounterModule.decrement();console.log(CounterModule.getCount()); // 1

// Tentative d'accès à la variable privéeconsole.log(CounterModule.count); // undefined

// Utilisation de la méthode publiqueCounterModule.setCount(10);console.log(CounterModule.getCount()); // 10


Avantages : encapsulation, réduction de la pollution de l'espace de noms global, réutilisabilité du code. Inconvénients : peut être moins efficace en mémoire que les classes, plus difficile à tester en isolation.



Conclusion

Les patrons de conception ne sont pas des recettes universelles, mais des outils puissants dans l'arsenal d'un développeur. En JavaScript, leur utilisation correcte permet de créer un code plus structuré, maintenable et évolutif. La clé est de comprendre quand et pourquoi appliquer un patron particulier, plutôt que d'essayer de les utiliser partout.



Commencez par les patrons Singleton, Factory, Observer et Module - ils couvrent la majorité des tâches typiques dans le développement web moderne. Avec l'expérience, vous apprendrez à reconnaître les situations où l'application d'un patron de conception sera vraiment bénéfique.

Blogs

Book Recommendations