Back

Qu'est-ce que le principe d'inversion de dépendance ? Expliqué simplement

Qu'est-ce que le principe d'inversion de dépendance ? Expliqué simplement

Le Principe d’Inversion de Dépendance (DIP) est l’un des cinq principes SOLID de la conception orientée objet. Il aide à créer des systèmes flexibles et découplés en inversant la direction de la dépendance — des implémentations concrètes vers des contrats abstraits. Cet article vous aidera à comprendre le DIP en langage simple, avec des exemples que vous pourrez appliquer immédiatement.

Points clés

  • Les modules de haut niveau ne devraient pas dépendre des modules de bas niveau ; les deux devraient dépendre d’abstractions
  • Le DIP permet une architecture flexible et testable
  • Vous verrez comment appliquer le DIP avec des exemples concrets dans plusieurs langages

La définition officielle

Les modules de haut niveau ne devraient pas dépendre des modules de bas niveau. Les deux devraient dépendre d’abstractions. Les abstractions ne devraient pas dépendre des détails. Les détails devraient dépendre des abstractions.

Décomposons cela :

  • Module de haut niveau : contient la logique métier (ex. passer une commande)
  • Module de bas niveau : gère des tâches spécifiques (ex. envoyer un email)
  • Abstraction : une interface ou une classe de base qui définit un comportement, pas une implémentation

Une analogie visuelle

Imaginez que vous avez un OrderService qui envoie une notification par email lorsqu’une commande est passée.

Sans DIP :

OrderService --> EmailService

OrderService est étroitement couplé à EmailService. Vous ne pouvez pas le remplacer ou le simuler facilement.

Avec DIP :

OrderService --> INotificationService <-- EmailService

Maintenant, les deux modules dépendent d’une abstraction (INotificationService).

Un exemple de code : sans DIP (TypeScript)

class EmailService {
  send(message: string) {
    console.log(`Sending email: ${message}`);
  }
}

class OrderService {
  constructor(private emailService: EmailService) {}

  placeOrder() {
    this.emailService.send("Order placed");
  }
}

Cela couple étroitement OrderService à EmailService.

Refactorisé : avec DIP (TypeScript)

interface INotificationService {
  send(message: string): void;
}

class EmailService implements INotificationService {
  send(message: string) {
    console.log(`Sending email: ${message}`);
  }
}

class OrderService {
  constructor(private notifier: INotificationService) {}

  placeOrder() {
    this.notifier.send("Order placed");
  }
}

DIP en Python

from abc import ABC, abstractmethod

class NotificationService(ABC):
    @abstractmethod
    def send(self, message: str):
        pass

class EmailService(NotificationService):
    def send(self, message: str):
        print(f"Sending email: {message}")

class OrderService:
    def __init__(self, notifier: NotificationService):
        self.notifier = notifier

    def place_order(self):
        self.notifier.send("Order placed")

# Utilisation
service = OrderService(EmailService())
service.place_order()

DIP en Java

interface NotificationService {
    void send(String message);
}

class EmailService implements NotificationService {
    public void send(String message) {
        System.out.println("Sending email: " + message);
    }
}

class OrderService {
    private NotificationService notifier;

    public OrderService(NotificationService notifier) {
        this.notifier = notifier;
    }

    public void placeOrder() {
        notifier.send("Order placed");
    }
}

// Utilisation
OrderService service = new OrderService(new EmailService());
service.placeOrder();

Pourquoi le DIP est important

  • Testabilité : Remplacez les dépendances réelles par des mocks ou des fakes
  • Flexibilité : Changez d’implémentation sans toucher à la logique de haut niveau
  • Séparation des préoccupations : Chaque module fait un travail et communique via des contrats

Idée reçue courante : DIP ≠ Injection de Dépendance

Ils sont liés, mais différents :

  • DIP concerne qui dépend de qui (direction de la dépendance)
  • L’Injection de Dépendance est une façon d’appliquer le DIP — en injectant des dépendances au lieu de les coder en dur

Quand utiliser le DIP

Utilisez-le quand :

  • Vous voulez écrire une logique métier qui ne se soucie pas de l’implémentation sous-jacente
  • Vous travaillez sur une application en couches ou modulaire
  • Vous construisez pour la testabilité ou l’extensibilité

Conclusion

Le Principe d’Inversion de Dépendance consiste à inverser la direction habituelle de la dépendance — de sorte que les abstractions, et non les implémentations, définissent votre architecture. Cela rend votre code plus réutilisable, testable et robuste face aux changements.

FAQ

C'est un principe de conception où les modules de haut niveau et les modules de bas niveau dépendent tous deux d'abstractions plutôt que les uns des autres.

Non. Le DIP est un principe. L'injection de dépendance est une technique pour mettre en œuvre le DIP.

Parce que vous pouvez remplacer les dépendances réelles par des mocks ou des stubs qui suivent la même interface.

Les interfaces aident en TypeScript, mais en JavaScript, vous pouvez utiliser des contrats de forme d'objet et des modèles pour obtenir le même résultat.

Listen to your bugs 🧘, with OpenReplay

See how users use your app and resolve issues fast.
Loved by thousands of developers