Aller au contenu principal

Dependency

🛠️ Pourquoi le DIP est-il important ?

AvantageExplication
DécouplageRéduit les dépendances directes entre les classes, facilitant l'évolution du code.
TestabilitéPermet de mocker facilement les dépendances pour les tests unitaires.
FlexibilitéOn peut changer les implémentations sans modifier le code client.

⚡ Note : Le DIP est essentiel pour construire des architectures modulaires et maintenables.


🪄 Comment appliquer le DIP ?

Pour respecter le DIP :

  1. Définir des interfaces pour les services ou dépendances.
  2. Injecter les dépendances via constructeur, méthode ou propriété.
  3. Éviter d'instancier directement des classes concrètes dans les modules de haut niveau.

ℹ️ Astuce : Chaque classe de haut niveau devrait interagir uniquement avec des abstractions, pas avec des implémentations concrètes.


📩 Exemple en C#

❌ Mauvaise pratique : Dépendance directe à une classe concrète

// Module de bas niveau
public class EmailService
{
public void SendEmail(string message)
{
// Logique d'envoi d'email
}
}

// Module de haut niveau (dépend directement de EmailService)
public class OrderProcessor
{
private readonly EmailService _emailService = new EmailService();

public void ProcessOrder()
{
// Traitement de la commande
_emailService.SendEmail("Votre commande a été traitée.");
}
}

ℹ️ Problème : OrderProcessor dépend directement d'une classe concrète, rendant le code rigide et difficile à tester.


✅ Bonne pratique : Dépendance inversée via une interface

// Abstraction (interface)
public interface IMessageService
{
void Send(string message);
}

// Module de bas niveau (implémente l'interface)
public class EmailService : IMessageService
{
public void Send(string message)
{
// Logique d'envoi d'email
}
}

// Autre implémentation possible
public class SmsService : IMessageService
{
public void Send(string message)
{
// Logique d'envoi de SMS
}
}

// Module de haut niveau (dépend de l'abstraction)
public class OrderProcessor
{
private readonly IMessageService _messageService;

// Injection de dépendance via le constructeur
public OrderProcessor(IMessageService messageService)
{
_messageService = messageService;
}

public void ProcessOrder()
{
_messageService.Send("Votre commande a été traitée.");
}
}

// Utilisation
var emailService = new EmailService();
var orderProcessor = new OrderProcessor(emailService);

// Ou avec un autre service
var smsService = new SmsService();
var orderProcessorSms = new OrderProcessor(smsService);

ℹ️ Avantages :

  • OrderProcessor dépend d'une abstraction (IMessageService) et non d'une implémentation concrète.
  • Facile de changer le service de messagerie sans modifier le code.
  • Tests unitaires simples grâce aux mocks.

⚡ Problèmes fréquents / Causes probables

SymptômeCause probableSolution
Code rigide et difficile à testerDépendance directe à des classes concrètesIntroduire des interfaces et injecter les dépendances
Modification d'un service casse le code clientCouplage fort entre haut et bas niveauAppliquer le DIP et dépendre uniquement d'abstractions
Tests unitaires complexes ou impossiblesAbsence d'abstractionsUtiliser des interfaces ou classes abstraites pour les dépendances

🎯 Conclusion

Le Dependency Inversion Principle permet de concevoir des systèmes modulaires, flexibles et testables. En dépendant d'abstractions plutôt que de détails, le code devient plus robuste, maintenable et évolutif.