December 20, 2025 (4mo ago) — last updated April 7, 2026 (14d ago)

Patrons de conception POO : guide pratique (TypeScript)

Maîtrisez les patrons POO (création, structurels, comportementaux) avec exemples TypeScript et conseils de refactoring pour un code plus maintenable.

← Back to blog
Cover Image for Patrons de conception POO : guide pratique (TypeScript)

Les patrons de conception sont des modèles éprouvés qui rendent votre code POO plus maintenable et évolutif. Ce guide pratique présente les patrons de création, structurels et comportementaux avec exemples TypeScript, conseils de refactoring et pièges à éviter pour améliorer la qualité de vos projets.

Guide pratique des patrons de conception en POO

Maîtrisez les patrons de conception en POO avec notre guide. Apprenez les patrons de création, structurels et comportementaux avec des exemples de code clairs et pratiques pour faire évoluer vos compétences.

Introduction

Les patrons de conception en programmation orientée objet sont des modèles réutilisables et éprouvés pour résoudre des problèmes de conception récurrents. Ce ne sont pas des bouts de code à copier-coller ; ce sont des gabarits adaptables qui aident à structurer classes et objets pour que le code soit plus facile à maintenir, étendre et tester. De nombreux développeurs considèrent les patrons comme indispensables pour la qualité du logiciel5.

Une bonne compréhension des patrons courants — de création, structurels et comportementaux — vous permet de communiquer clairement l’intention de conception avec vos coéquipiers, de refactorer du code ancien en toute sécurité et de choisir le bon outil pour chaque problème architectural.

Qu’est-ce que les patrons de conception en programmation orientée objet

Vous avez déjà essayé de construire quelque chose de complexe sans plan ? Coder sans patrons de conception peut conduire à une base de code emmêlée, difficile à faire évoluer et à maintenir. Les patrons de conception sont comme le livre de recettes d’un chef : des recettes testées que vous adaptez pour obtenir des résultats cohérents et maintenables.2

Un croquis d'une toque de chef laissant tomber des formes de lettres dorées dans un livre de recettes ouvert.

Le langage partagé des développeurs

Un des avantages les plus précieux des patrons est un vocabulaire commun. Dites “Factory” ou “Singleton” et les développeurs expérimentés comprennent immédiatement l’intention et la structure générale, ce qui accélère la collaboration et les décisions architecturales.

“Design Patterns: Elements of Reusable Object-Oriented Software,” publié en 1994 par Erich Gamma, Richard Helm, Ralph Johnson et John Vlissides, a catalogué 23 patrons fondamentaux qui restent une lecture essentielle pour les praticiens de la POO2. Ces patrons s’appuient sur des travaux académiques antérieurs montrant des gains mesurables de productivité et de réutilisation dans de grands projets1.

Un patron de conception n’est pas une conception finie qui peut être transformée directement en code. C’est une description ou un modèle de la façon de résoudre un problème qui peut être utilisé dans de nombreuses situations différentes.

Se familiariser avec les principes de base de la POO comme le polymorphisme et l’héritage vous aide à appliquer les patrons efficacement. Pour un rappel pratique, consultez notre comparatif sur le polymorphisme et l’héritage : polymorphism vs inheritance.

Les trois catégories principales de patrons de conception

Le Gang of Four a organisé les patrons en trois catégories : création, structurels et comportementaux. Connaître ces catégories vous aide à choisir rapidement l’approche adaptée à un problème.

Schéma illustrant les patrons de conception créatifs, structurels et comportementaux avec de simples illustrations en boîte.

Aperçu des catégories de patrons de conception en POO

Catégorie de patronObjectif principalExemples courants
CréationGérer et abstraire la création d'objetsFactory, Builder, Singleton, Prototype
StructurelComposer classes et objets en structures plus larges et flexiblesAdapter, Decorator, Facade, Composite
ComportementalDéfinir comment les objets interagissent et communiquentObserver, Strategy, Command, Iterator

Patrons de création : les spécialistes de la construction

Les patrons de création contrôlent la manière dont les objets sont créés pour que le code client ne soit pas fortement couplé aux classes concrètes. Ils cachent la logique de création, augmentent la flexibilité et vous permettent de gérer l’instanciation (par exemple, en imposant une instance unique avec Singleton).

Patrons structurels : la colle architecturale

Les patrons structurels vous aident à assembler des objets en systèmes plus larges. Ils simplifient les relations entre composants pour que vous puissiez changer des parties sans casser l’ensemble. Des patrons comme Adapter permettent à des interfaces incompatibles de coopérer, ce qui est inestimable lors de l’intégration de bibliothèques tierces.

Les patrons structurels simplifient la conception du système en identifiant des moyens simples de réaliser les relations entre entités.

Patrons comportementaux : les directeurs de la communication

Les patrons comportementaux régissent l’interaction et la responsabilité des objets. Ils créent des canaux de communication propres — Observer pour les notifications événementielles et Strategy pour remplacer des algorithmes sans modifier les clients.

En gérant soigneusement les chemins de communication, vous réduisez les dépendances et facilitez la compréhension et la maintenance de la base de code.

Créer des objets avec les patrons de création

Les patrons de création introduisent une couche d’abstraction autour de la création d’objets, afin que vous puissiez échanger des implémentations sans changer le code client. Voici deux exemples pratiques en TypeScript : Singleton et Factory Method.

Une illustration contrastant des objets individuels en forme d'œuf avec une chaîne de montage d'usine produisant des éléments colorés.

Le patron Singleton : garantir une seule vraie instance

Singleton garantit qu’une classe n’a qu’une seule instance et fournit un point d’accès global. Il est utile pour des ressources partagées comme une connexion à la base de données ou un logger, mais il peut introduire un état global qui complique les tests et la gestion des dépendances3.

Exemple : un Singleton TypeScript pour une connexion à la base de données.

class DatabaseConnection {
  private static instance: DatabaseConnection;

  private constructor() {
    // A private constructor prevents external 'new' calls
    console.log("Connecting to the database...");
  }

  public static getInstance(): DatabaseConnection {
    if (!DatabaseConnection.instance) {
      DatabaseConnection.instance = new DatabaseConnection();
    }
    return DatabaseConnection.instance;
  }

  public query(sql: string): void {
    console.log(`Executing query: ${sql}`);
  }
}

// Usage
const db1 = DatabaseConnection.getInstance();
const db2 = DatabaseConnection.getInstance();

db1.query("SELECT * FROM users");
console.log(db1 === db2); // true

Le compromis du Singleton : utilisez les Singletons pour des ressources réellement globales, et préférez l’injection de dépendances pour une meilleure testabilité et modularité3.

Le Factory Method : laisser les sous-classes décider quoi créer

Factory Method définit une interface pour créer un objet, tandis que les sous-classes décident quel produit concret instancier. Il découple le code client des classes concrètes, rendant le système plus facile à étendre.

Exemple : rendre des boutons spécifiques au système d’exploitation en TypeScript.

interface Button {
  render(): void;
  onClick(f: () => void): void;
}

class WindowsButton implements Button {
  render() { console.log("Rendering a button in Windows style."); }
  onClick(f: () => void) { console.log("Windows button click event."); f(); }
}

class MacButton implements Button {
  render() { console.log("Rendering a button in macOS style."); }
  onClick(f: () => void) { console.log("Mac button click event."); f(); }
}

abstract class Dialog {
  abstract createButton(): Button;

  render() {
    const okButton = this.createButton();
    okButton.render();
  }
}

class WindowsDialog extends Dialog {
  createButton(): Button { return new WindowsButton(); }
}

class MacDialog extends Dialog {
  createButton(): Button { return new MacButton(); }
}

// Client
const os: string = "windows";
let dialog: Dialog;
if (os === "windows") dialog = new WindowsDialog(); else dialog = new MacDialog();
dialog.render();

Factory Method garde le créateur ignorant des produits concrets, ce qui rend l’ajout de choses comme LinuxDialog simple.

Construire des systèmes flexibles avec les patrons structurels

Les patrons structurels vous aident à composer des objets en systèmes robustes et adaptables. Deux choix pratiques sont Adapter et Decorator.

Illustrations faites à la main d'un adaptateur électrique et d'une pile d'anneaux représentant des patrons de conception POO.

Le patron Adapter : combler des interfaces incompatibles

Adapter enveloppe une interface incompatible pour qu’elle corresponde à ce que votre système attend. Cela évite des changements invasifs dans du code legacy.

Exemple : adapter un ModernLogger à une interface ILogger existante.

class ModernLogger {
  public logInfo(message: string): void {
    console.log(`[INFO]: ${message}`);
  }
}

interface ILogger { log(message: string): void; }

class LoggerAdapter implements ILogger {
  private modernLogger: ModernLogger;
  constructor() { this.modernLogger = new ModernLogger(); }
  public log(message: string): void { this.modernLogger.logInfo(message); }
}

const logger: ILogger = new LoggerAdapter();
logger.log("User logged in successfully.");

Le patron Decorator : ajouter des fonctionnalités dynamiquement

Decorator ajoute des responsabilités aux objets à l’exécution en les enveloppant. C’est plus flexible que l’héritage et respecte le principe de responsabilité unique.

Exemple : composer une souscription avec des options supplémentaires facultatives.

interface Subscription { getDescription(): string; getCost(): number; }

class BasicSubscription implements Subscription {
  getDescription(): string { return "Basic Plan"; }
  getCost(): number { return 10; }
}

abstract class SubscriptionDecorator implements Subscription {
  protected subscription: Subscription;
  constructor(subscription: Subscription) { this.subscription = subscription; }
  abstract getDescription(): string;
  abstract getCost(): number;
}

class PremiumSupportDecorator extends SubscriptionDecorator {
  getDescription(): string { return `${this.subscription.getDescription()}, Premium Support`; }
  getCost(): number { return this.subscription.getCost() + 5; }
}

class CloudStorageDecorator extends SubscriptionDecorator {
  getDescription(): string { return `${this.subscription.getDescription()}, 1TB Cloud Storage`; }
  getCost(): number { return this.subscription.getCost() + 7; }
}

let mySubscription: Subscription = new BasicSubscription();
mySubscription = new PremiumSupportDecorator(mySubscription);
mySubscription = new CloudStorageDecorator(mySubscription);
console.log(mySubscription.getDescription());
console.log(mySubscription.getCost());

Cette approche compositionnelle garde les fonctionnalités modulaires et faciles à tester.

Gérer les interactions avec les patrons comportementaux

Les patrons comportementaux organisent la communication entre objets pour que les systèmes restent flexibles et maintenables. Deux exemples centraux sont Observer et Strategy.

Le patron Observer : notifier les parties intéressées

Observer met en place une relation un-à-plusieurs afin que lorsqu’un Sujet change d’état, les Observers soient notifiés automatiquement. Il est idéal pour les systèmes pilotés par les événements.

Exemple : un service de notification simple.

interface Subject { attach(observer: Observer): void; detach(observer: Observer): void; notify(): void; }
interface Observer { update(subject: Subject): void; }

class NotificationService implements Subject {
  public state: string = '';
  private observers: Observer[] = [];
  attach(observer: Observer): void { this.observers.push(observer); }
  detach(observer: Observer): void { const i = this.observers.indexOf(observer); if (i !== -1) this.observers.splice(i, 1); }
  notify(): void { for (const o of this.observers) o.update(this); }
  public createNewPost(title: string): void { this.state = `New Post: ${title}`; console.log(`\nNotificationService: A new post was created.`); this.notify(); }
}

class EmailNotifier implements Observer { public update(subject: Subject): void { if (subject instanceof NotificationService) console.log(`EmailNotifier: Sending email about "${subject.state}"`); } }
class PushNotifier implements Observer { public update(subject: Subject): void { if (subject instanceof NotificationService) console.log(`PushNotifier: Sending push notification for "${subject.state}"`); } }

const notificationService = new NotificationService();
const emailer = new EmailNotifier();
const pusher = new PushNotifier();
notificationService.attach(emailer);
notificationService.attach(pusher);
notificationService.createNewPost("Understanding Observer Pattern");
notificationService.detach(pusher);
notificationService.createNewPost("Why Strategy is Awesome");

Observer produit un design faiblement couplé : les Sujets n’ont pas besoin de connaître les Observers concrets qu’ils notifient.

Le patron Strategy : encapsuler des algorithmes

Strategy vous permet d’échanger des algorithmes à l’exécution, évitant de grands blocs conditionnels. Il est en accord avec le principe Open/Closed en permettant de nouvelles stratégies sans modifier le code existant4.

Exemple : stratégies de paiement pour un panier d’achat.

interface PaymentStrategy { pay(amount: number): void; }
class CreditCardStrategy implements PaymentStrategy { pay(amount: number): void { console.log(`Paying $${amount} with Credit Card.`); } }
class PayPalStrategy implements PaymentStrategy { pay(amount: number): void { console.log(`Paying $${amount} via PayPal.`); } }

class ShoppingCart {
  private paymentStrategy: PaymentStrategy;
  constructor(strategy: PaymentStrategy) { this.paymentStrategy = strategy; }
  public setPaymentStrategy(strategy: PaymentStrategy) { this.paymentStrategy = strategy; }
  public checkout(amount: number): void { this.paymentStrategy.pay(amount); }
}

const cart = new ShoppingCart(new CreditCardStrategy());
cart.checkout(150);
cart.setPaymentStrategy(new PayPalStrategy());
cart.checkout(150);

Strategy élimine la complexité conditionnelle et facilite l’extensibilité des systèmes.

Pièges courants de conception et stratégies de refactoring

Choisir un patron n’est qu’une moitié de la bataille. Évitez les anti-patrons comme l’objet Dieu (God Object), qui accumule des responsabilités et viole le principe de responsabilité unique. Recherchez les odeurs de code — méthodes longues, dépendances excessives ou classes monstres — et corrigez-les avec un refactoring discipliné.

Le refactoring consiste à améliorer la structure interne sans changer le comportement externe. C’est ainsi que l’on dompte les systèmes legacy en toute sécurité.

Refactorer vers le patron Strategy

Un grand switch ou une longue chaîne if/else est une odeur classique. Refactorez en extrayant le comportement variable dans une interface Strategy avec des classes de stratégie concrètes. Remplacez la condition par un seul appel à la méthode de la stratégie sélectionnée. Ce changement améliore l’extensibilité, la testabilité et l’alignement avec les principes SOLID4.

Réponses à vos questions sur les patrons de conception POO

Combien de patrons devrais-je apprendre ?

Concentrez-vous d’abord sur 5 à 7 patrons essentiels : Singleton, Factory, Adapter, Decorator, Observer et Strategy. Apprenez le problème que chaque patron résout ; une fois que vous l’avez intégré, il est beaucoup plus facile d’apprendre des patrons supplémentaires.

Quand devrais-je éviter d’utiliser un patron ?

Évitez les patrons qui ajoutent de la complexité sans résoudre un vrai problème. N’introduisez pas un patron « au cas où ». Suivez le principe YAGNI : ajoutez des patrons lorsqu’un problème clair et présent le justifie.

Puis-je utiliser des patrons de conception avec la programmation fonctionnelle ?

Oui. Beaucoup de patrons se mappent naturellement aux techniques fonctionnelles. Strategy peut être des paramètres de fonction, et Decorator peut être des fonctions d’ordre supérieur. L’important est d’appliquer le principe sous-jacent plutôt que de copier rigidement les formes POO.


Chez Clean Code Guy, nous aidons les équipes à construire des logiciels qui durent en intégrant des principes fondamentaux dans leur flux de travail. Découvrez comment nos audits de code et notre refactoring prêt pour l’IA peuvent permettre à votre équipe de livrer en toute confiance sur https://cleancodeguy.com.

Questions fréquentes (Q&A)

Q: Par où commencer pour apprendre les patrons ?

A: Commencez par 5 à 7 patrons essentiels (voir ci‑dessus), implémentez-les en petits projets et relisez des exemples en TypeScript pour solidifier les concepts.

Q: Comment choisir entre un patron et une solution simple ?

A: Mesurez la complexité et la fréquence du changement. Si la solution propre et simple suffit aujourd’hui, évitez d’introduire un patron. Ajoutez‑le quand le besoin de flexibilité ou de testabilité apparaît.

Q: Mes équipes doivent-elles documenter les patrons utilisés ?

A: Oui. Documenter l’intention, le compromis et un exemple de mise en œuvre réduit les malentendus et accélère l’onboarding.

1.
W. G. Griswold et al., “A Formal Foundation for Design Pattern Abstraction and Reuse,” Proceedings of ECOOP ’93, University of California, San Diego. https://cseweb.ucsd.edu/~wgg/CSE210/ecoop93-patterns.pdf
2.
Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1994). https://en.wikipedia.org/wiki/Design_Patterns
3.
Martin Fowler, “Singleton,” Bliki, discusses Singleton trade-offs and testing implications. https://martinfowler.com/bliki/Singleton.html
4.
Robert C. Martin (Uncle Bob), “The SOLID Principles,” which explain Open/Closed and related design goals. https://8thlight.com/blog/uncle-bob/2012/08/13/the-s-o-l-i-d-principles.html
5.
Stack Overflow, Developer Survey and industry reports indicating that many developers value design patterns for maintainability and communication. https://insights.stackoverflow.com/survey
← Back to blog
🙋🏻‍♂️

L’IA écrit du code.
Vous le faites durer.

À l’ère de l’accélération de l’IA, le code propre n’est pas seulement une bonne pratique — c’est la différence entre les systèmes qui évoluent et les codebases qui s’effondrent sous leur propre poids.