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.
Injection de dépendances (DI) est une technique dans laquelle une classe reçoit ses dépendances de l’extérieur au lieu de les créer elle-même. Cela rend le code plus flexible, testable et faiblement couplé.
Sans DI, une classe crée ses propres dépendances, ce qui rend leur modification ou leur test difficiles :
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 un expéditeur d’e-mails, de SMS ou un expéditeur simulé 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éeCe modèle suit le principe de dépendre des abstractions (interfaces) plutôt que des implémentations concrètes. Il permet de remplacer les implémentations sans modifier la classe qui les utilise, ce qui est essentiel pour les tests unitaires et la maintenance d’architectures flexibles.
Défi
FacileConstruisons 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, capable de fonctionner avec n’importe quelle destination de journalisation — console, simulation de fichier ou autre — sans connaître les détails spécifiques.
Vous allez organiser votre code sur trois fichiers :
ILogWriter.cs: définissez une interface appeléeILogWriterdans l’espace de nomsLogging. Cette interface représente le contrat de toute destination de journalisation et doit comporter une seule méthodeWrite(string message)qui renvoie une chaîne décrivant l’endroit où le message a été écrit.LogWriters.cs: créez deux implémentations concrètes deILogWriterdans l’espace de nomsLogging:ConsoleLogWriter— sa méthodeWriterenvoieConsole: {message}FileLogWriter— reçoit un nom de fichier via son constructeur et sa méthodeWriterenvoieFile[{filename}]: {message}
Logger.cs: créez une classeLoggerdans l’espace de nomsLoggingqui reçoit sa dépendance par injection via le constructeur. La classeLoggerdoit :- Accepter un
ILogWritervia son constructeur et le stocker dans un champ privé - Disposer d’une méthode
Log(string message)qui délègue l’opération au générateur de journaux injecté et renvoie le résultat
- Accepter un
Program.cs: démontrez l’injection de dépendances en créant deux générateurs de journaux différents — l’un avec unConsoleLogWriteret l’autre avec unFileLogWriter. Montrez comment la même classeLoggerse comporte différemment selon la dépendance injectée.
Vous recevrez deux entrées :
- Le nom de fichier pour le générateur de journaux de fichier
- Le message à journaliser
Créez un Logger avec un ConsoleLogWriter et journalisez le message. Créez ensuite un autre Logger avec un FileLogWriter (en utilisant le nom de fichier fourni en 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 doit être :
Console: System started
File[app.log]: System startedRemarquez que la classe Logger ne change jamais : elle fonctionne avec toute implémentation de ILogWriter. C’est l’essence de l’injection de dépendances : Logger dépend d’une abstraction (l’interface), et l’implémentation concrète est « injectée » depuis l’extérieur. Vous pourriez facilement ajouter plus tard un DatabaseLogWriter ou un CloudLogWriter sans modifier du tout la classe Logger !
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
}
}
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
1Fondamentaux de la POO
Fichiers externesEspaces de noms et directivesIntro aux classes et objetsLe mot-clé 'this'Méthodes et paramètresChamps vs PropriétésConstructeursInitialiseurs d'objetsRécapitulatif - Calculatrice simple4Héritage
Syntaxe de base de l'héritage (:)Le mot-clé 'base'Mots-clés Virtual & OverrideClasses scelléesLa classe de base 'object'Récapitulatif - Hiérarchie des employés7Fonctionnalités avancées
Surcharge d'opérateursIndexeurs (this[])Redéfinition de ToString()Méthodes d'extensionRécapitulatif - Liste personnalisée10Patrons de conception - Partie 1
Introduction aux patrons de conceptionSingleton Thread-SafePatron FabriquePatron Observateur (Événements)Patron Stratégie2Propriétés et membres statiques
Propriétés auto-implémentéesPropriétés en lecture/écriture seuleChamps et méthodes statiquesClasses statiquesMembres à corps d'expression5Polymorphisme & Interfaces
Polymorphisme : Compilation vs ExécutionInterface vs Classe AbstraiteInterfaces MultiplesInterfaces ExplicitesUpcasting & DowncastingRécapitulatif - Calculateur de Formes8Concepts avancés de la POO
Composition plutôt qu'héritageGénériques (Classes et Méthodes)Délégués et ÉvénementsAttributs et RéflexionIDisposable et l'instruction usingBases de l'Injection de Dépendances11Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode TemplatePatron ÉtatPatron Composite3Architecture des classes
Données d'instance vs statiquesMots-clés 'readonly' & 'const'Champs de supportRécapitulatif - Gestionnaire de compte bancaire6Encapsulation
Modificateurs d'accèsPropriétés pour l'encapsulationImplémentation du masquage de donnéesPatterns d'immuabilitéRécapitulatif - Dossiers d'étudiants12Projet : Système de gestion de bibliothèque
Structure du projetModèles Livre et UtilisateurLogique du système d'empruntLINQ pour la rechercheInterface Console / Interface d'administrationTests unitaires (NUnit/xUnit)Entraînez-vous par vous-même : Compilateur C# en ligne