Inversion of Control 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.
Il s'agit d'un principe de conception dans lequel le flux de contrôle est «reçu» de la bibliothèque générique écrite ou du code réutilisable.
Pour mieux le comprendre, voyons comment nous codions 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 revanche, avec l'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 comme 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 appellent mon code logique métier (lorsqu'un événement est déclenché) et NON 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 graphique d'objet global et des relations entre les différents objets.
L'injection de dépendance est un modèle de conception qui met en œuvre le principe IoC pour résoudre les dépendances des objets.
En termes plus simples, lorsque vous essayez d'écrire du code, vous créerez et utiliserez 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 analogie simple 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épendance suggère qu'au lieu que les classes dépendantes (Class Car ici) créent ses dépendances (moteur de classe et classe 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 fournit à 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'à un beau jour où un utilisateur commence à écrire le français dans l'éditeur.
Pour prendre en charge plus de langues, nous devons avoir plus de vérificateurs orthographiques. Probablement français, allemand, espagnol, etc.
Ici, nous avons créé un code étroitement couplé avec SpellChecker "anglais" étant é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. Ainsi, 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.
Maintenant, la dépendance peut être injectée dans le constructeur, une propriété publique ou une méthode.
Essayons de changer notre classe en utilisant le constructeur 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é à l'instance de TextEditor.
Vous pouvez lire l'article complet ici