4 Design Patterns incontournables : pour un code élégant et performant !

Les Design Patterns ne sont pas qu'un jargon de développeurs chevronnés ! Ce sont des solutions éprouvées qui transforment la manière dont vous abordez vos projets. Que ce soit pour rendre votre code plus modulaire, évolutif ou tout simplement plus clair, ces outils peuvent changer votre quotidien. Dans cet article, nous allons explorer quelques patterns incontournables, comprendre pourquoi ils sont essentiels et comment les appliquer efficacement.
design pattern.jpg
IMG_6199 1(1).jpeg
Nathan MITTELETTE, M. propre du codelogo Linkedin
M. Propre du Code dans le podcast AXOPEN, je suis toujours en quête d'optimisation et de performance dans mes projets ! #JAVA #DevOps #SpringMis à jour le 19 Mars 2025

17+

ans
d'experience

60+

experts
techniques

100K

écoutes de notre podcast
logo Axopen

Pourquoi les Design Patterns sont-ils indispensables ?

  • Un langage commun pour une meilleure collaboration : Les Design Patterns offrent un vocabulaire partagé au sein des équipes. Plutôt que d'expliquer des concepts complexes, vous pouvez dire : « Utilisons le pattern Observer ici ». Cela aligne tout le monde rapidement.
  • Des solutions éprouvées à des problèmes récurrents : Inutile de réinventer la roue ! Ces patterns sont des réponses testées à des défis communs du développement, ce qui améliore la qualité et la maintenabilité de votre code.
  • Une transversalité Frontend/Backend : Qu'il s'agisse de gestion d'événements en frontend ou de modularité en backend, les Design Patterns sont universels et renforcent votre polyvalence en tant que développeur.

Focus sur 4 design patterns incontournables

Je vous propose de nous concentrer aujourd'hui sur 4 Design Patterns incontournables que j'utilise au quotidien !

Le Pattern Proxy : L'intermédiaire invisible mais indispensable

Vous utilisez probablement des Proxys sans même le savoir. Imaginez un intermédiaire capable de gérer, enrichir ou sécuriser les interactions entre un client et un service :

  • Suivi des modifications
  • Optimisation via le cache
  • Gestion des transactions et sécurité

Exemples concrets :

  • Dans les ORMs (comme Entity Framework), les Proxys optimisent les requêtes SQL.
  • Avec Spring Boot, ils automatisent la gestion des transactions ou de la sécurité.
  • Les Reverse Proxys (comme Nginx) améliorent les performances et sécurisent vos services.

Voici une illustration du fonctionnement qu'un Proxy peut avoir lorsque l'on souhaite mettre automatiquement en cache des retours de fonction : Image not found


Le Pattern Observer : L'écoute proactive du code

Imaginez : au lieu de vérifier en boucle si votre pizza est prête, votre four vous envoie un message. C'est exactement ce que fait le pattern Observer : il notifie automatiquement vos applications des changements !

Avantages :

  • Fini le polling incessant ! Les Observateurs s'abonnent à un sujet et sont notifiés en temps réel.
  • Un code plus clair et découplé : les sujets et observateurs restent indépendants.

Applications pratiques :

  • Les frameworks comme Angular utilisent des Observables (RxJS) pour gérer les événements.
  • Les apps mobiles exploitent ce pattern pour rafraîchir les interfaces dynamiquement.

Attention : Pensez bien à vous désabonner quand un Observateur n'est plus nécessaire pour éviter les fuites mémoire !


type Observer = (message: string) => void;

class Subject {

  private observers: Observer[] = [];

  addObserver(observer: Observer): void {
    this.observers.push(observer);
  }

  removeObserver(observer: Observer): void {
    this.observers = this.observers.filter(obs => obs !== observer);
  }

  notify(message: string): void {
    this.observers.forEach(observer => observer(message));
  }

}

const observer: Observer = (message: string) => console.log(`Received message : ${message}`);

subject.addObserver(observer);
subject.notify('IMPORTANT MESSAGE TO SHARE');
subject.removeObserver(observer);

Le Pattern Strategy : Modularité et flexibilité à l'honneur

Le Strategy Pattern brille par sa simplicité : il permet d'implémenter plusieurs variantes d'un comportement, sans alourdir votre code avec des conditions complexes.

Principes clés :

  • Chaque stratégie est encapsulée dans une classe dédiée.
  • Combinez ce pattern avec l'injection de dépendances pour configurer facilement quelle stratégie appliquer.

Exemple :

Plutôt que d'avoir un switch interminable dans une classe, choisissez dynamiquement la méthode adaptée en fonction du contexte. Cela améliore la lisibilité, la maintenance et la réutilisabilité de votre code.

// Interface Strategy : définit une méthode commune pour toutes les stratégies

interface Strategy {
    void execute();
}

// Implémentation 1 : Stratégie A

class StrategyA implements Strategy {
    public void execute() {
        console.log("Exécution de la stratégie A");
    }
}

// Implémentation 2 : Stratégie B

class StrategyB implements Strategy {
    public void execute() {
        console.log("Exécution de la stratégie B");
    }
}

// Contexte : utilise une stratégie sans connaître son implémentation concrète

class Context {
    private Strategy strategy;

    constructor(private readonly strategy: Strategy) {}

    // La méthode 'apply' appelle la méthode 'execute' de la stratégie actuelle
    // Avantage : le contexte n'a pas besoin de savoir quelle est l'implémentation utilisée.
    // Il se contente d'utiliser la méthode 'execute()' définie par l'interface.
    public void apply() {
        this.strategy.execute();
    }
}

Le Pattern Singleton : Une seule instance pour gouverner toutes les autres

Le Singleton est un design pattern simple mais puissant, idéal pour garantir qu'une classe donnée n'a qu'une seule instance partagée dans l'ensemble d'un projet.

Quand utiliser le Singleton ?

  • Lorsque vous avez besoin d'une ressource globale partagée, comme une configuration, un logger ou une connexion à une base de données.
  • Dans les petits projets, il peut être une alternative rapide et légère à une injection de dépendances.

Singleton et Scopes en développement

Le Singleton est souvent mentionné aux côtés d'autres scopes dans des frameworks modernes comme .NET ou NestJS. Voici un aperçu des trois principaux scopes :

  1. Singleton
    • Une seule instance est créée et partagée tout au long de la durée de vie de l'application.
    • Exemples : Services comme la configuration ou le caching.
  2. Scoped
    • Une instance est créée pour chaque requête ou contexte spécifique.
    • Exemples : Services d'accès aux données dans des API, où chaque utilisateur bénéficie de sa propre instance.
  3. Transient
    • Une nouvelle instance est créée à chaque utilisation.
    • Exemples : Services à usage unique, ou quand les données doivent être isolées.

Attention !

Le Singleton peut devenir un anti-pattern s'il est mal utilisé. Sur des projets complexes, il peut introduire des dépendances cachées difficiles à maintenir. Soyez vigilant !


public class Singleton {

    private static Singleton _instance;

    // Si _instance est différent de null on le retourne
    // Sinon on crée une nouvelle instance
    public static Singleton Instance => _instance ??= new Singleton();

    // Constructeur privé pour empêcher l'instanciation directe
    private Singleton() { }

    public void DoSomething() {
        Console.WriteLine("Singleton en action !");
    }
}

// Exemple d'utilisation

class Program {
    static void Main() {
        Singleton.Instance.DoSomething();
    }
}

Les design patterns : une approche pragmatique pour un code robuste !

Maîtriser les Design Patterns, c'est comme apprendre une langue universelle pour le développement. Cela vous rend plus efficace, améliore la qualité de vos projets et renforce votre collaboration avec vos équipes.

Mais si j'ai un conseil à vous donner, soyez curieux ! Je viens de vous montrer 4 design patterns incontournables à mes yeux, mais il en existe encore plein d'autres ! Et, même si vous ne les utilisez pas au quotidien, c'est important de les connaître. Cela permet d'avoir toute une palette d'outils pour répondre aux nombreuses problématiques que vous rencontrerez dans votre vie de développeur (et on le sait, elles sont nombreuses !).

Bon après, vous n'allez pas tout résoudre avec des Design Patterns, mais c'est une très bonne base de réflexion :) Maintenant, à vous de savoir quand il est pertinent de les utiliser sur vos projets !