L’inversion de la dépendance en C#
L’inversion de dépendence est un principe important pour écrire du code maintenable. Dans cet article nous voyons un exemple d’application en C#.
Introduction & définition
L’inversion de dépendance est un des principes de l’approche SOLID. Elle traite de la question du couplage entre les différentes classes ou modules de votre application.
L’inversion de dépendance fait intervenir les notions de classe supérieure et de classes inférieures. La classe supérieure dépend d’une ou de plusieurs classes inférieures. La devise principale de l’inversion de dépendance est Toute classe supérieure devrait toujours dépendre de l’abstraction de la classe inférieure plutôt que de l’implémentation de cette dernière.
Enoncer ce principe via sa devise ne suffit pas saisir entièrement ce que l’inversion de dépendance représente en réalité. Nous allons donc écrire du code C# pour voir l’application de ce principe en action.
Exemple
Pour mieux saisir le principe de l’inversion de dépendance, il me semble pertinent d’étudier un exemple pratique.
Supposons que nous ayons une classe principale (supérieure) nommée TradeProcessor
. Cette classe se charge de lire des données à partir d’une source, puis elle retraite les données brutes et les stocke quelque part.
Elle dépend des trois classes suivantes :
DataProvider
qui fournit à la classe un ensemble de méthodes pour récupérer les données brutes.DataParser
qui est une classe qui contient des méthodes pour traiter les données et les rendre prêtes à stocker.DataStorage
qui est une classe qui se charge de stocker les données dans une base de données et d’écrire des logs.
Implémentation sans inversion de dépendance
Nous présentons un à un le code de chacune de ces classes.
La classe TradeProcessor
La classe DataProvider
La classe DataParser
La classe DataStorage
Implémentation avec l’inversion de la dépendance
L’idée ici c’est de faire en sorte que la classe TradeProcessor
ne dépende pas des classes inférieures mais qu’elle dépende plutôt des abastractions de ces classes.
L’élement que nous utilisons pour l’abastraction est justement une interface.
Nous avons extrait les interfaces des classes inférieures, voilà donc comment nous implémentons la classe TradeProcessor
, nous donnons le nom de TradeProcessorDI
.
Vous remarquerez que peu de choses diffèrent entre les classes TradeDataProcessor
et TradeDataProcessorDI
. En fait nous avons seulement remplacé les noms des classes inférieures par les noms de leurs interfaces.
La classe fonctionne exactement pareil.
La méthode Main
de notre programme fonctionne exactement pareil avec les deux classes TradeDataProcessor
et TradeDataProcessorDI
Quel intérêt ?
Vous pouvez vous dire mais à quoi ça sert de faire toute cette bidouille pour arriver à la même solution qu’avec la première classe.
En fait nous venons d’inverser les dépendances de la classe TradeDataProcessor. Cela signifie que la classe TradeDataProcessorDI peut prendre en argument dans son constructeur non seulement les classe DataProvider
, DataParser
et DataStorage
mais aussi n’importe quelle classe qui implémente les interfaces IDataProvider
, IDataParser
et IDataStorage
.