Principe d'inversion de dépendance vs «Programmer vers une interface, pas une implémentation»
12
J'essaie de comprendre en quoi le principe d'inversion de dépendance diffère du principe «programme à une interface, pas une implémentation».
Je comprends ce que signifie «Programmer vers une interface, pas une implémentation». Je comprends également comment cela permet des conceptions plus flexibles et plus faciles à entretenir.
Mais je ne comprends pas en quoi le principe d'inversion de dépendance est différent du principe «programme à une interface, pas une implémentation».
J'ai lu sur DIP à plusieurs endroits sur le Web, et cela n'a pas dissipé ma confusion. Je ne vois toujours pas en quoi les deux principes diffèrent l'un de l'autre. Merci de votre aide.
«Programmer vers une interface» signifie ne pas dépendre d'un type concret pour faire votre travail , mais il ne spécifie pas comment vous devez obtenir votre dépendance.
Le "Principe d'inversion des dépendances" dit qu'un objet ne doit pas contrôler la création de ses dépendances, il doit simplement annoncer les dépendances dont il a besoin et laisser l'appelant les lui fournir . Mais il ne précise pas si la dépendance doit être un type concret ou une interface.
Je vais illustrer les différences avec du code C #.
L'exemple suivant dépend d'un type concret et contrôle sa propre création de dépendance. Il ne suit ni "programme vers une interface" ni "inversion de dépendance":
public class ThingProcessor
{
MyThing _myThing;
public ThingProcessor()
{
_myThing = new MyThing();
}
public void DoSomething()
{
_myThing.DoIt();
}
}
L'exemple suivant dépend d'une interface, mais il contrôle la création de sa propre dépendance. Il suit "programme vers une interface", mais pas "inversion de dépendance":
public class ThingProcessor
{
IMyThing _myThing;
public ThingProcessor()
{
_myThing = ThingFactory.GiveMeANewMyThing();
}
public void DoSomething()
{
_myThing.DoIt();
}
}
L'exemple suivant dépend d'un type concret, mais il demande que sa dépendance soit créée et lui soit transmise. Il suit "l'inversion de dépendance", mais pas "programme vers une interface":
public class ThingProcessor
{
MyThing _myThing;
public ThingProcessor(MyThing myThing)
{
_myThing = myThing;
}
public void DoSomething()
{
_myThing.DoIt();
}
}
L'exemple suivant dépend d'une interface, et il demande que sa dépendance soit créée et lui soit transmise. Il suit à la fois "inversion de dépendance" et "programme vers une interface":
public class ThingProcessor
{
IMyThing _myThing;
public ThingProcessor(IMyThing myThing) // using an interface
{
_myThing = myThing;
}
public void DoSomething()
{
_myThing.DoIt();
}
}
Ce dont vous parlez, c'est d'une injection dépendante. Et l'inversion de dépendance et l'injection de dépendance sont deux choses différentes.
Euphoric
1
@Euphoric Je parle du principe d'inversion de dépendance, qui est un concept abstrait, en utilisant l'injection de dépendance comme exemple d'implémentation concrète. Je comprends la différence.
Eric King
1
@EricKing Alors vous devriez dire explicitement que dans votre réponse au lieu d'aller "Le" Principe d'inversion de dépendance "dit ..." ce qui est évidemment faux si vous lisez ma réponse.
Euphoric
1
Je suis d'accord avec Euphoric. Le principe d'inversion de dépendance dit que les couches de code de niveau supérieur devraient dépendre de morceaux de code de niveau inférieur, et non l'inverse. Par exemple, cela PrintStreamdevrait dépendre de l'interface établie par ByteOutputStream. L'injection de dépendance ne mentionne rien qui devrait dépendre de qui.
Les modules de haut niveau ne doivent pas dépendre de modules de bas niveau. Les deux devraient dépendre des abstractions.
Les abstractions ne devraient jamais dépendre des détails. Les détails doivent dépendre des abstractions.
L'interface est une abstraction et la mise en œuvre est un détail. Si vous les remplacez dans les deux instructions précédentes, vous obtenez essentiellement "le code doit dépendre des interfaces et non des implémentations". Et cela me semble la même chose.
Cela devrait être la réponse acceptée, l'autre réponse la plus votée est trompeuse
Sameh Deabes
2
Les interfaces sont un moyen d'implémenter DI. Si vous spécifiez une interface en tant que paramètre dans la méthode constructeur d'une classe, vous pouvez remettre tout objet que vous aimez à cette méthode constructeur, tant que cet objet implémente l'interface du paramètre constructeur.
En d'autres termes, la programmation d'une interface vous permet de modifier l'implémentation de cette interface. C'est ainsi que nous pouvons substituer des objets fictifs à des objets réels lors des tests unitaires, spécifier différents fournisseurs de données, etc.
PrintStream
devrait dépendre de l'interface établie parByteOutputStream
. L'injection de dépendance ne mentionne rien qui devrait dépendre de qui.Ils sont généralement la même chose. Si vous lisez Qu'est-ce que le principe d'inversion de dépendance et pourquoi est-il important? et le principe d'inversion de dépendance , vous vous rendrez compte que les deux "principes" parlent essentiellement de la même chose.
L'interface est une abstraction et la mise en œuvre est un détail. Si vous les remplacez dans les deux instructions précédentes, vous obtenez essentiellement "le code doit dépendre des interfaces et non des implémentations". Et cela me semble la même chose.
la source
Les interfaces sont un moyen d'implémenter DI. Si vous spécifiez une interface en tant que paramètre dans la méthode constructeur d'une classe, vous pouvez remettre tout objet que vous aimez à cette méthode constructeur, tant que cet objet implémente l'interface du paramètre constructeur.
En d'autres termes, la programmation d'une interface vous permet de modifier l'implémentation de cette interface. C'est ainsi que nous pouvons substituer des objets fictifs à des objets réels lors des tests unitaires, spécifier différents fournisseurs de données, etc.
la source