Menu
Coddy logo textTech

Bases de l'Injection de Dépendances

Fait partie de la section Programmation Orientée Objet du Journey C# de Coddy — leçon 46 sur 70.

L'injection de dépendances (DI) est une technique par laquelle une classe reçoit ses dépendances de l'extérieur plutôt que de les créer elle-même. Cela rend le code plus flexible, testable et faiblement couplé.

Sans l'injection de dépendances (DI), une classe crée ses propres dépendances, ce qui la rend difficile à modifier ou à tester :

public class OrderService
{
    private EmailSender sender = new EmailSender();  // Fortement couplé
    
    public void PlaceOrder() => sender.Send("Order placed");
}

Avec l'injection de dépendances (DI), les dépendances sont transmises via le constructeur :

public interface IMessageSender
{
    void Send(string message);
}

public class EmailSender : IMessageSender
{
    public void Send(string message) => Console.WriteLine("Email: " + message);
}

public class OrderService
{
    private IMessageSender sender;
    
    public OrderService(IMessageSender sender)
    {
        this.sender = sender;
    }
    
    public void PlaceOrder() => sender.Send("Order placed");
}

Désormais, OrderService ne sait pas et ne se soucie pas de savoir s'il utilise l'e-mail, le SMS ou un expéditeur fictif pour les tests. La dépendance est « injectée » lors de la création de l'objet :

IMessageSender emailSender = new EmailSender();
OrderService service = new OrderService(emailSender);
service.PlaceOrder();  // Email : Commande passée

Ce patron suit le principe de dépendance envers les abstractions (interfaces) plutôt que les implémentations concrètes. Il permet d'échanger les implémentations sans modifier la classe qui les utilise, ce qui est essentiel pour les tests unitaires et le maintien d'architectures flexibles.

challenge icon

Défi

Facile

Construisons un système de journalisation qui démontre la puissance de l'injection de dépendances. Au lieu de coder en dur la manière dont les journaux sont écrits, vous allez créer une classe Logger flexible qui peut fonctionner avec n'importe quelle destination de journalisation — console, simulation de fichier, ou n'importe quoi d'autre — sans en connaître les spécificités.

Vous organiserez votre code sur trois fichiers :

  • ILogWriter.cs : Définissez une interface nommée ILogWriter dans l'espace de noms Logging. Cette interface représente le contrat pour toute destination de journalisation et doit posséder une seule méthode Write(string message) qui retourne une chaîne de caractères décrivant où le message a été écrit.
  • LogWriters.cs : Créez deux implémentations concrètes de ILogWriter dans l'espace de noms Logging :
    • ConsoleLogWriter - sa méthode Write retourne "Console: " + message
    • FileLogWriter - prend un nom de fichier via son constructeur et sa méthode Write retourne "File[" + filename + "]: " + message
  • Logger.cs : Créez une classe Logger dans l'espace de noms Logging qui reçoit sa dépendance par injection de constructeur. Le Logger doit :
    • Accepter un ILogWriter via son constructeur et le stocker dans un champ privé
    • Avoir une méthode Log(string message) qui délègue au rédacteur (writer) injecté et retourne le résultat
  • Program.cs : Démontrez l'injection de dépendances en créant deux loggers différents — l'un avec un ConsoleLogWriter et l'autre avec un FileLogWriter. Montrez comment la même classe Logger se comporte différemment selon la dépendance qui est injectée.

Vous recevrez deux entrées :

  • Le nom de fichier pour le logger de fichier
  • Le message à journaliser

Créez un Logger avec un ConsoleLogWriter et journalisez le message. Ensuite, créez un autre Logger avec un FileLogWriter (en utilisant le nom de fichier provenant de l'entrée) et journalisez le même message. Affichez chaque résultat sur sa propre ligne.

Par exemple, si les entrées sont app.log et System started, la sortie devrait être :

Console: System started
File[app.log]: System started

Remarquez comment la classe Logger ne change jamais — elle fonctionne avec n'importe quelle implémentation de ILogWriter. C'est l'essence même de l'injection de dépendances : le Logger dépend d'une abstraction (l'interface), et l'implémentation concrète est « injectée » de l'extérieur. Vous pourriez facilement ajouter un DatabaseLogWriter ou un CloudLogWriter plus tard sans modifier la classe Logger du tout !

Aide-mémoire

L'injection de dépendances (DI) est une technique par laquelle une classe reçoit ses dépendances de l'extérieur plutôt que de les créer elle-même, ce qui rend le code plus flexible, testable et faiblement couplé.

Sans DI (fortement couplé) :

public class OrderService
{
    private EmailSender sender = new EmailSender();  // Tightly coupled
    
    public void PlaceOrder() => sender.Send("Order placed");
}

Avec DI (faiblement couplé) :

public interface IMessageSender
{
    void Send(string message);
}

public class EmailSender : IMessageSender
{
    public void Send(string message) => Console.WriteLine("Email: " + message);
}

public class OrderService
{
    private IMessageSender sender;
    
    public OrderService(IMessageSender sender)
    {
        this.sender = sender;
    }
    
    public void PlaceOrder() => sender.Send("Order placed");
}

Injection de la dépendance :

IMessageSender emailSender = new EmailSender();
OrderService service = new OrderService(emailSender);
service.PlaceOrder();  // Email: Order placed

La DI suit le principe de dépendance envers les abstractions (interfaces) plutôt qu'envers les implémentations concrètes, permettant de changer d'implémentation sans modifier la classe qui les utilise.

Essayez vous-même

using System;
using Logging;

class Program
{
    public static void Main(string[] args)
    {
        // Lire les entrées
        string filename = Console.ReadLine();
        string message = Console.ReadLine();

        // TODO: Créer un Logger avec un ConsoleLogWriter et journaliser le message
        // Afficher le résultat

        // TODO: Créer un autre Logger avec un FileLogWriter (en utilisant le filename) et journaliser le même message
        // Afficher le résultat
    }
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet