L'inversion de contrôle est un principe de conception générique de l'architecture logicielle qui aide à créer des cadres logiciels modulaires réutilisables et faciles à entretenir.
C'est un principe de conception dans lequel le flux de contrôle est "reçu" de la bibliothèque générique ou du code réutilisable.
Pour mieux le comprendre, voyons comment nous avions l'habitude de coder dans nos premiers jours de codage. Dans les langages procéduraux / traditionnels, la logique métier contrôle généralement le flux de l'application et «appelle» le code / les fonctions génériques ou réutilisables. Par exemple, dans une application console simple, mon flux de contrôle est contrôlé par les instructions de mon programme, qui peuvent inclure les appels à certaines fonctions générales réutilisables.
print ("Please enter your name:");
scan (&name);
print ("Please enter your DOB:");
scan (&dob);
//More print and scan statements
<Do Something Interesting>
//Call a Library function to find the age (common code)
print Age
En contraste, avec IoC, les Frameworks sont le code réutilisable qui «appelle» la logique métier.
Par exemple, dans un système basé sur Windows, un cadre sera déjà disponible pour créer des éléments d'interface utilisateur tels que des boutons, des menus, des fenêtres et des boîtes de dialogue. Lorsque j'écris la logique métier de mon application, ce sont les événements du framework qui appelleront mon code de logique métier (lorsqu'un événement est déclenché) et PAS l'inverse.
Bien que le code du framework ne connaisse pas ma logique métier, il saura toujours comment appeler mon code. Ceci est réalisé en utilisant des événements / délégués, des rappels, etc. Ici, le contrôle du flux est "inversé".
Ainsi, au lieu de dépendre du flux de contrôle sur des objets liés statiquement, le flux dépend du graphe d'objets global et des relations entre les différents objets.
L'injection de dépendances est un modèle de conception qui implémente le principe IoC pour résoudre les dépendances d'objets.
En termes plus simples, lorsque vous essayez d'écrire du code, vous créez et utilisez différentes classes. Une classe (classe A) peut utiliser d'autres classes (classe B et / ou D). Ainsi, les classes B et D sont des dépendances de la classe A.
Une simple analogie sera une voiture de classe. Une voiture peut dépendre d'autres classes comme le moteur, les pneus et plus encore.
L'injection de dépendances suggère qu'au lieu que les classes dépendantes (Class Car ici) créent ses dépendances (Class Engine et class Tire), la classe devrait être injectée avec l'instance concrète de la dépendance.
Permet de comprendre avec un exemple plus pratique. Considérez que vous écrivez votre propre TextEditor. Entre autres choses, vous pouvez avoir un correcteur orthographique qui offre à l'utilisateur la possibilité de vérifier les fautes de frappe dans son texte. Une implémentation simple d'un tel code peut être:
Class TextEditor
{
//Lot of rocket science to create the Editor goes here
EnglishSpellChecker objSpellCheck;
String text;
public void TextEditor()
{
objSpellCheck = new EnglishSpellChecker();
}
public ArrayList <typos> CheckSpellings()
{
//return Typos;
}
}
À première vue, tout semble rose. L'utilisateur écrira du texte. Le développeur capturera le texte et appellera la fonction CheckSpellings et trouvera une liste de fautes de frappe qu'il montrera à l'utilisateur.
Tout semble bien fonctionner jusqu'au jour où un utilisateur commence à écrire le français dans l'éditeur.
Pour fournir la prise en charge de plusieurs langues, nous avons besoin de plus de vérificateurs d'orthographe. Probablement français, allemand, espagnol, etc.
Ici, nous avons créé un code étroitement couplé avec SpellChecker "anglais" étroitement couplé à notre classe TextEditor, ce qui signifie que notre classe TextEditor dépend de EnglishSpellChecker ou en d'autres termes, EnglishSpellCheker est la dépendance de TextEditor. Nous devons supprimer cette dépendance. De plus, notre éditeur de texte a besoin d'un moyen de conserver la référence concrète de tout correcteur orthographique en fonction de la discrétion du développeur au moment de l'exécution.
Ainsi, comme nous l'avons vu dans l'introduction de DI, cela suggère que la classe devrait être injectée avec ses dépendances. Donc, il devrait être de la responsabilité du code appelant d'injecter toutes les dépendances dans la classe / le code appelé. Nous pouvons donc restructurer notre code comme
interface ISpellChecker
{
Arraylist<typos> CheckSpelling(string Text);
}
Class EnglishSpellChecker : ISpellChecker
{
public override Arraylist<typos> CheckSpelling(string Text)
{
//All Magic goes here.
}
}
Class FrenchSpellChecker : ISpellChecker
{
public override Arraylist<typos> CheckSpelling(string Text)
{
//All Magic goes here.
}
}
Dans notre exemple, la classe TextEditor doit recevoir l'instance concrète de type ISpellChecker.
Désormais, la dépendance peut être injectée dans Constructor, une propriété publique ou une méthode.
Essayons de changer notre classe en utilisant Constructor DI. La classe TextEditor modifiée ressemblera à quelque chose comme:
Class TextEditor
{
ISpellChecker objSpellChecker;
string Text;
public void TextEditor(ISpellChecker objSC)
{
objSpellChecker = objSC;
}
public ArrayList <typos> CheckSpellings()
{
return objSpellChecker.CheckSpelling();
}
}
Pour que le code appelant, lors de la création de l'éditeur de texte, puisse injecter le type SpellChecker approprié dans l'instance de TextEditor.
Vous pouvez lire l'article complet ici