L'inversion de contrôle (IoC) peut être assez déroutante lorsqu'elle est rencontrée pour la première fois.
- Qu'Est-ce que c'est?
- Quel problème résout-il?
- Quand est-il approprié d'utiliser et quand non?
L'inversion de contrôle (IoC) peut être assez déroutante lorsqu'elle est rencontrée pour la première fois.
Réponses:
Les modèles d'inversion de contrôle (IoC) et d'injection de dépendance (DI) visent à supprimer les dépendances de votre code.
Par exemple, supposons que votre application possède un composant éditeur de texte et que vous souhaitiez effectuer une vérification orthographique. Votre code standard ressemblerait à ceci:
public class TextEditor {
private SpellChecker checker;
public TextEditor() {
this.checker = new SpellChecker();
}
}
Ce que nous avons fait ici crée une dépendance entre le TextEditor
et le SpellChecker
. Dans un scénario IoC, nous ferions plutôt quelque chose comme ceci:
public class TextEditor {
private IocSpellChecker checker;
public TextEditor(IocSpellChecker checker) {
this.checker = checker;
}
}
Dans le premier exemple de code, nous instancions SpellChecker
( this.checker = new SpellChecker();
), ce qui signifie que la TextEditor
classe dépend directement de la SpellChecker
classe.
Dans le deuxième exemple de code, nous créons une abstraction en ayant la SpellChecker
classe de dépendance dans TextEditor
la signature du constructeur de (pas en initialisant la dépendance dans la classe). Cela nous permet d'appeler la dépendance puis de la passer à la classe TextEditor comme ceci:
SpellChecker sc = new SpellChecker; // dependency
TextEditor textEditor = new TextEditor(sc);
Maintenant, le client qui crée la TextEditor
classe a le contrôle sur l' SpellChecker
implémentation à utiliser car nous injectons la dépendance dans la TextEditor
signature.
Inversion de contrôle est ce que vous obtenez lorsque votre programme rappelle, par exemple comme un programme GUI.
Par exemple, dans un menu old school, vous pourriez avoir:
print "enter your name"
read name
print "enter your address"
read address
etc...
store in database
contrôlant ainsi le flux d'interaction de l'utilisateur.
Dans un programme GUI ou un peu, au lieu de cela, nous disons:
when the user types in field a, store it in NAME
when the user types in field b, store it in ADDRESS
when the user clicks the save button, call StoreInDatabase
Alors maintenant, le contrôle est inversé ... au lieu que l'ordinateur accepte les entrées de l'utilisateur dans un ordre fixe, l'utilisateur contrôle l'ordre dans lequel les données sont entrées et le moment où les données sont enregistrées dans la base de données.
Fondamentalement, tout ce qui a une boucle d'événements, des rappels ou des déclencheurs d'exécution tombe dans cette catégorie.
Qu'est-ce que l'inversion de contrôle?
Si vous suivez ces deux étapes simples, vous avez effectué une inversion de contrôle:
Il existe plusieurs techniques possibles pour chacune de ces étapes en fonction de la technologie / du langage que vous utilisez pour votre implémentation.
-
La partie inversion de l'inversion de contrôle (IoC) est une chose déroutante; parce que l' inversion est le terme relatif. La meilleure façon de comprendre l'IoC est d'oublier ce mot!
-
Exemples
what-to-do
etwhen-to-do
L'inversion des contrôles consiste à séparer les préoccupations.
Sans IoC : vous avez un ordinateur portable et vous cassez accidentellement l'écran. Et sacrément, vous trouverez le même modèle d'écran d'ordinateur portable nulle part sur le marché. Vous êtes donc coincé.
Avec IoC : vous avez un ordinateur de bureau et vous cassez accidentellement l'écran. Vous constatez que vous pouvez simplement saisir presque n'importe quel moniteur de bureau sur le marché, et cela fonctionne bien avec votre bureau.
Votre bureau implémente avec succès l'IoC dans ce cas. Il accepte une variété de moniteurs, contrairement à l'ordinateur portable, il a besoin d'un écran spécifique pour être réparé.
L'inversion de contrôle (ou IoC), c'est obtenir la liberté (vous vous mariez, vous avez perdu la liberté et vous êtes contrôlé. Vous avez divorcé, vous venez de mettre en œuvre l'inversion de contrôle. C'est ce que nous avons appelé "découplé". Bon système informatique décourage certaines relations très étroites.) plus de flexibilité (la cuisine de votre bureau ne sert que de l'eau du robinet propre, c'est votre seul choix lorsque vous voulez boire. Votre patron a mis en place l'inversion de contrôle en installant une nouvelle machine à café. flexibilité de choisir de l'eau du robinet ou du café.) et moins de dépendance (Votre partenaire a un travail, vous n'avez pas de travail, vous dépendez financièrement de votre partenaire, donc vous êtes contrôlé. Vous trouvez un travail, vous avez mis en œuvre l'inversion de contrôle. Un bon système informatique encourage l'indépendance.)
Lorsque vous utilisez un ordinateur de bureau, vous avez asservi (ou dites contrôlé). Vous devez vous asseoir devant un écran et le regarder. Utiliser le clavier pour taper et utiliser la souris pour naviguer. Et un logiciel mal écrit peut vous asservir encore plus. Si vous remplacez votre ordinateur de bureau par un ordinateur portable, vous avez quelque peu inversé le contrôle. Vous pouvez facilement le prendre et vous déplacer. Alors maintenant, vous pouvez contrôler où vous êtes avec votre ordinateur, au lieu de le contrôler.
En implémentant Inversion of Control, un consommateur de logiciel / objet obtient plus de contrôles / d'options sur le logiciel / les objets, au lieu d'être contrôlé ou d'avoir moins d'options.
Avec les idées ci-dessus à l'esprit. Nous manquons encore un élément clé de l'IoC. Dans le scénario IoC, le consommateur de logiciel / objet est un cadre sophistiqué. Cela signifie que le code que vous avez créé n'est pas appelé par vous-même. Expliquons maintenant pourquoi cette méthode fonctionne mieux pour une application Web.
Supposons que votre code soit un groupe de travailleurs. Ils ont besoin de construire une voiture. Ces travailleurs ont besoin d'un endroit et d'outils (un cadre logiciel) pour construire la voiture. UNE framework logiciel traditionnel sera comme un garage avec de nombreux outils. Les travailleurs doivent donc établir eux-mêmes un plan et utiliser les outils pour construire la voiture. Construire une voiture n'est pas une entreprise facile, il sera très difficile pour les travailleurs de planifier et de coopérer correctement. UNE modernele cadre logiciel sera comme une usine automobile moderne avec toutes les installations et les gestionnaires en place. Les travailleurs n'ont pas à faire de plan, les gestionnaires (qui font partie du cadre, ils sont les personnes les plus intelligentes et ont élaboré le plan le plus sophistiqué) aideront à coordonner afin que les travailleurs sachent quand faire leur travail (le cadre appelle votre code). Les travailleurs doivent simplement être suffisamment flexibles pour utiliser tous les outils que les gestionnaires leur donnent (en utilisant l'injection de dépendance).
Bien que les travailleurs donnent le contrôle de la gestion du projet au plus haut niveau aux gestionnaires (le cadre). Mais il est bon que certains professionnels aident. C'est le concept de l'IoC qui vient vraiment.
Les applications Web modernes avec une architecture MVC dépendent du cadre pour effectuer le routage d'URL et mettre en place des contrôleurs pour le cadre à appeler.
L'injection de dépendance et l'inversion du contrôle sont liées. L'injection de dépendance est au niveau micro et l'inversion de contrôle est au niveau macro . Vous devez manger chaque bouchée (implémenter DI) pour terminer un repas (implémenter IoC).
Avant d'utiliser Inversion of Control, vous devez être bien conscient du fait qu'il a ses avantages et ses inconvénients et vous devez savoir pourquoi vous l'utilisez si vous le faites.
Avantages:
Les inconvénients:
Personnellement, je vois les points forts de l'IoC et je les aime vraiment, mais j'ai tendance à éviter l'IoC autant que possible car cela transforme votre logiciel en une collection de classes qui ne constituent plus un "vrai" programme mais juste quelque chose qui doit être mis en place par Configuration XML ou métadonnées d'annotation et s'effondreraient (et s'effondreraient) sans elle.
Article Wikipédia . Pour moi, l'inversion du contrôle transforme votre code écrit séquentiellement et le transforme en une structure de délégation. Au lieu que votre programme contrôle tout explicitement, votre programme met en place une classe ou une bibliothèque avec certaines fonctions à appeler lorsque certaines choses se produisent.
Il résout la duplication de code. Par exemple, autrefois, vous écriviez manuellement votre propre boucle d'événements, interrogeant les bibliothèques système pour de nouveaux événements. De nos jours, la plupart des API modernes vous permettent simplement d'indiquer aux bibliothèques système les événements qui vous intéressent, et cela vous permettra de savoir quand ils se produisent.
L'inversion de contrôle est un moyen pratique de réduire la duplication de code, et si vous vous retrouvez à copier une méthode entière et à ne modifier qu'une petite partie du code, vous pouvez envisager de le résoudre avec l'inversion de contrôle. L'inversion du contrôle est facilitée dans de nombreux langages grâce au concept de délégués, d'interfaces ou même de pointeurs de fonctions brutes.
Il n'est pas approprié de l'utiliser dans tous les cas, car le déroulement d'un programme peut être plus difficile à suivre lorsqu'il est écrit de cette façon. C'est un moyen utile de concevoir des méthodes lors de l'écriture d'une bibliothèque qui sera réutilisée, mais elle doit être utilisée avec parcimonie dans le cœur de votre propre programme, sauf si elle résout vraiment un problème de duplication de code.
Mais je pense que vous devez être très prudent avec cela. Si vous abusez de ce modèle, vous ferez une conception très compliquée et du code encore plus compliqué.
Comme dans cet exemple avec TextEditor: si vous n'avez qu'un seul correcteur orthographique, il n'est peut-être pas vraiment nécessaire d'utiliser IoC? Sauf si vous avez besoin d'écrire des tests unitaires ou quelque chose ...
Quoi qu'il en soit: soyez raisonnable. Les modèles de conception sont de bonnes pratiques, mais pas la Bible à prêcher. Ne le collez pas partout.
Pour moi, l'IoC / DI repousse les dépendances vers les objets appelants. Super simple.
La réponse non technique est de pouvoir remplacer un moteur dans une voiture juste avant de l'allumer. Si tout se branche bien (l'interface), vous êtes bon.
Supposons que vous soyez un objet. Et vous allez au restaurant:
Sans IoC : vous demandez "pomme", et on vous sert toujours des pommes quand vous en demandez plus.
Avec IoC : vous pouvez demander des "fruits". Vous pouvez obtenir des fruits différents à chaque fois que vous êtes servi. par exemple, pomme, orange ou melon d'eau.
Donc, évidemment, l'IoC est préférable lorsque vous aimez les variétés.
L'inversion de contrôle est un modèle utilisé pour découpler les composants et les couches dans le système. Le modèle est implémenté en injectant des dépendances dans un composant lors de sa construction. Ces dépendances sont généralement fournies en tant qu'interfaces pour un découplage ultérieur et pour prendre en charge la testabilité. Les conteneurs IoC / DI tels que Castle Windsor, Unity sont des outils (bibliothèques) qui peuvent être utilisés pour fournir l'IoC. Ces outils offrent des fonctionnalités étendues au-delà de la simple gestion des dépendances, y compris la durée de vie, AOP / Interception, la politique, etc.
une. Évite à un composant d'être responsable de la gestion de ses dépendances.
b. Fournit la possibilité d'échanger des implémentations de dépendance dans différents environnements.
c. Permet à un composant d'être testé en se moquant des dépendances.
ré. Fournit un mécanisme de partage des ressources dans une application.
une. Critique lors du développement piloté par les tests. Sans IoC, il peut être difficile de tester, car les composants testés sont fortement couplés au reste du système.
b. Critique lors du développement de systèmes modulaires. Un système modulaire est un système dont les composants peuvent être remplacés sans nécessiter de recompilation.
c. Critique s'il existe de nombreuses préoccupations transversales qui doivent être traitées, en particulier dans une application d'entreprise.
Répondre à la première partie seulement. Qu'Est-ce que c'est?
L'inversion de contrôle (IoC) signifie créer des instances de dépendances en premier et dernier exemple d'une classe (en les injectant éventuellement via le constructeur), au lieu de créer d'abord une instance de la classe puis l'instance de classe en créant des instances de dépendances. Ainsi, l'inversion de contrôle inverse le flux de contrôle du programme. Au lieu que l' appelé contrôle le flux de contrôle (tout en créant des dépendances), l' appelant contrôle le flux de contrôle du programme .
Je noterai ma simple compréhension de ces deux termes:
For quick understanding just read examples*
Injection de dépendance (DI): L'
injection de dépendance signifie généralement passer un objet dont la méthode dépend, en tant que paramètre à une méthode, plutôt que de demander à la méthode de créer l'objet dépendant .
En pratique, cela signifie que la méthode ne dépend pas directement d'une implémentation particulière; toute implémentation qui répond aux exigences peut être transmise en tant que paramètre.
Avec ces objets, dites leurs dépendances. Et le printemps le rend disponible.
Cela conduit à un développement d'applications faiblement couplé.
Quick Example:EMPLOYEE OBJECT WHEN CREATED,
IT WILL AUTOMATICALLY CREATE ADDRESS OBJECT
(if address is defines as dependency by Employee object)
Conteneur d'inversion de contrôle (IoC):
C'est une caractéristique commune des frameworks, IOC gère les objets java
- de l'instanciation à la destruction via sa BeanFactory.
-Les composants Java qui sont instanciés par le conteneur IoC sont appelés beans, et le conteneur IoC gère la portée d'un bean, les événements de cycle de vie et toutes les fonctionnalités AOP pour lesquelles il a été configuré et codé.
QUICK EXAMPLE:Inversion of Control is about getting freedom, more flexibility, and less dependency. When you are using a desktop computer, you are slaved (or say, controlled). You have to sit before a screen and look at it. Using keyboard to type and using mouse to navigate. And a bad written software can slave you even more. If you replaced your desktop with a laptop, then you somewhat inverted control. You can easily take it and move around. So now you can control where you are with your computer, instead of computer controlling it
.
En implémentant Inversion of Control, un consommateur de logiciels / d'objets obtient plus de contrôles / d'options sur les logiciels / objets, au lieu d'être contrôlé ou d'avoir moins d'options.
L'inversion du contrôle en tant que guide de conception sert les objectifs suivants:
Il y a un découplage entre l'exécution d'une certaine tâche et la mise en œuvre.
Chaque module peut se concentrer sur ce pour quoi il est conçu.
Les modules ne font aucune hypothèse sur ce que font les autres systèmes mais s'appuient sur leurs contrats.
Le remplacement des modules n'a aucun effet secondaire sur les autres modules
Je vais garder les choses abstraites ici, vous pouvez visiter les liens suivants pour une compréhension détaillée du sujet.
Une bonne lecture avec exemple
Je suis d'accord avec NilObject , mais j'aimerais ajouter à cela:
si vous vous retrouvez à copier une méthode entière et à ne changer qu'une petite partie du code, vous pouvez envisager de l'aborder avec une inversion de contrôle
Si vous vous retrouvez à copier et coller du code, vous faites presque toujours quelque chose de mal. Codifié comme principe de conception une fois et une seule fois .
Par exemple, la tâche n ° 1 consiste à créer un objet. Sans concept IOC, la tâche n ° 1 est censée être effectuée par le programmeur, mais avec le concept IOC, la tâche n ° 1 serait effectuée par conteneur.
En bref, le contrôle est inversé du programmeur au conteneur. Ainsi, il est appelé inversion de contrôle.
J'ai trouvé un bon exemple ici .
Disons que nous faisons une réunion dans un hôtel.
Beaucoup de gens, beaucoup de carafes d'eau, beaucoup de gobelets en plastique.
Quand quelqu'un veut boire, elle remplit la tasse, boit et jette la tasse par terre.
Après une heure ou quelque chose, nous avons un sol couvert de gobelets en plastique et d'eau.
Laissez inverser le contrôle.
La même réunion au même endroit, mais au lieu de gobelets en plastique, nous avons un serveur avec une tasse en verre (Singleton)
et elle offre tout le temps aux invités à boire.
Quand quelqu'un veut boire, elle sort du verre du serveur, boit et le rend au serveur.
Laissant de côté la question de l'hygiène, la dernière forme de contrôle du processus de consommation est beaucoup plus efficace et économique.
Et c'est exactement ce que fait le Spring (un autre conteneur IoC, par exemple: Guice). Au lieu de laisser l'application créer ce dont elle a besoin en utilisant un nouveau mot-clé (prendre un gobelet en plastique), le conteneur Spring IoC offre tout le temps à l'application la même instance (singleton) de l'objet nécessaire (verre d'eau).
Considérez-vous comme l'organisateur d'une telle réunion. Vous avez besoin d'un moyen de signaler à l'administration de l'hôtel que
les membres de la réunion auront besoin d'un verre d'eau mais pas d'un morceau de gâteau.
Exemple:-
public class MeetingMember {
private GlassOfWater glassOfWater;
...
public void setGlassOfWater(GlassOfWater glassOfWater){
this.glassOfWater = glassOfWater;
}
//your glassOfWater object initialized and ready to use...
//spring IoC called setGlassOfWater method itself in order to
//offer to meetingMember glassOfWater instance
}
Liens utiles:-
Il semble que la chose la plus déroutante à propos de "IoC" l'acronyme et le nom qu'il représente est qu'il est trop glamour d'un nom - presque un nom de bruit.
Avons-nous vraiment besoin d'un nom pour décrire la différence entre la programmation procédurale et la programmation pilotée par les événements? D'accord, si nous en avons besoin, mais devons-nous choisir un tout nouveau nom «plus grand que nature» qui confond plus qu'il ne résout?
L'inversion du contrôle, c'est quand vous allez à l'épicerie et que votre femme vous donne la liste des produits à acheter.
En termes de programmation, elle a transmis une fonction de rappel getProductList()
à la fonction que vous exécutez - doShopping()
.
Il permet à l'utilisateur de la fonction d'en définir certaines parties, ce qui la rend plus flexible.
getProductList()
vous appelle, vous devez trouver la source de l'argent, signifie que le contrôle est à vos côtés. En cas d'inversion, elle contrôlera, c'est-à-dire l'argent qu'elle fournira également pour acheter.
J'ai trouvé un exemple très clair ici qui explique comment le «contrôle est inversé.
Code classique (sans injection de dépendance)
Voici comment fonctionne un code n'utilisant pas DI:
Utilisation de l'injection de dépendance
Voici comment fonctionne un code utilisant DI:
Le contrôle des dépendances est inversé de celui qui est appelé à celui qui appelle.
Quels problèmes cela résout-il?
L'injection de dépendances facilite l'échange avec les différentes implémentations des classes injectées. Lors des tests unitaires, vous pouvez injecter une implémentation factice, ce qui facilite considérablement les tests.
Ex: Supposons que votre application stocke le fichier téléchargé par l'utilisateur dans Google Drive, avec DI votre code de contrôleur peut ressembler à ceci:
class SomeController
{
private $storage;
function __construct(StorageServiceInterface $storage)
{
$this->storage = $storage;
}
public function myFunction ()
{
return $this->storage->getFile($fileName);
}
}
class GoogleDriveService implements StorageServiceInterface
{
public function authenticate($user) {}
public function putFile($file) {}
public function getFile($file) {}
}
Lorsque vos besoins changent, par exemple, au lieu de GoogleDrive, vous êtes invité à utiliser Dropbox. Il vous suffit d'écrire une implémentation de dropbox pour StorageServiceInterface. Vous n'avez aucune modification à apporter au contrôleur tant que l'implémentation de Dropbox adhère à StorageServiceInterface.
Pendant les tests, vous pouvez créer la maquette pour StorageServiceInterface avec l'implémentation factice où toutes les méthodes renvoient null (ou toute valeur prédéfinie selon vos exigences de test).
Au lieu de cela, si vous aviez la classe contrôleur pour construire l'objet de stockage avec le new
mot clé comme ceci:
class SomeController
{
private $storage;
function __construct()
{
$this->storage = new GoogleDriveService();
}
public function myFunction ()
{
return $this->storage->getFile($fileName);
}
}
Lorsque vous souhaitez changer avec l'implémentation Dropbox, vous devez remplacer toutes les lignes où new
objet GoogleDriveService est construit et utiliser DropboxService. En outre, lors du test de la classe SomeController, le constructeur attend toujours la classe GoogleDriveService et les méthodes réelles de cette classe sont déclenchées.
Quand est-ce approprié et quand non? À mon avis, vous utilisez DI lorsque vous pensez qu'il existe (ou qu'il peut y avoir) des implémentations alternatives d'une classe.
Une explication écrite très simple peut être trouvée ici
http://binstock.blogspot.in/2008/01/excellent-explanation-of-dependency.html
Ça dit -
"Toute application non triviale est composée de deux classes ou plus qui collaborent pour exécuter une logique métier. Traditionnellement, chaque objet est responsable d'obtenir ses propres références aux objets avec lesquels il collabore (ses dépendances). Lors de l'application de DI, le les objets reçoivent leurs dépendances au moment de la création par une entité externe qui coordonne chaque objet dans le système. En d'autres termes, les dépendances sont injectées dans les objets. "
L'inversion de contrôle est un principe générique, tandis que l'injection de dépendances réalise ce principe comme un modèle de conception pour la construction de graphes d'objets (c'est-à-dire que la configuration contrôle la façon dont les objets se référencent les uns les autres, plutôt que l'objet lui-même contrôlant comment obtenir la référence à un autre objet).
En regardant l'inversion du contrôle comme modèle de conception, nous devons examiner ce que nous inversons. L'injection de dépendance inverse le contrôle de la construction d'un graphe d'objets. Si elle est dite en termes simples, l'inversion de contrôle implique un changement de flux de contrôle dans le programme. Par exemple. Dans l'application autonome traditionnelle, nous avons la méthode principale, à partir de laquelle le contrôle est passé à d'autres bibliothèques tierces (dans le cas où nous avons utilisé la fonction de bibliothèque tierce), mais par l'inversion du contrôle, le contrôle est transféré du code de bibliothèque tiers vers notre code , car nous prenons le service d'une bibliothèque tierce. Mais il y a d'autres aspects qui doivent être inversés dans un programme - par exemple l'invocation de méthodes et de threads pour exécuter le code.
Pour ceux qui souhaitent approfondir l'inversion du contrôle, un article a été publié décrivant une image plus complète de l'inversion du contrôle en tant que modèle de conception (OfficeFloor: utiliser les modèles de bureau pour améliorer la conception de logiciels http://doi.acm.org/10.1145/ 2739011.2739013 avec une copie gratuite disponible en téléchargement sur http://www.officefloor.net/about.html ).
Ce qui est identifié est la relation suivante:
Inversion de contrôle (pour les méthodes) = Dépendance (état) Injection + Continuation Injection + Thread Injection
Résumé de la relation ci-dessus pour l'inversion de contrôle disponible - http://dzone.com/articles/inversion-of-coupling-control
L'IoC consiste à inverser la relation entre votre code et le code tiers (bibliothèque / framework):
DI (Dependency Injection) concerne la façon dont le contrôle circule dans l'application. L'application de bureau traditionnelle avait un flux de contrôle de votre application (méthode main ()) vers d'autres appels de méthode de bibliothèque, mais avec le flux de contrôle DI est inversé, le cadre prend soin de démarrer votre application, de l'initialiser et d'appeler vos méthodes chaque fois que nécessaire.
En fin de compte, vous gagnez toujours :)
J'aime cette explication: http://joelabrahamsson.com/inversion-of-control-an-introduction-with-examples-in-net/
Il démarre simplement et montre également des exemples de code.
Le consommateur, X, a besoin de la classe consommée, Y, pour accomplir quelque chose. C'est tout bon et naturel, mais X a-t-il vraiment besoin de savoir qu'il utilise Y?
N'est-ce pas suffisant que X sache qu'il utilise quelque chose qui a le comportement, les méthodes, les propriétés, etc. de Y sans savoir qui implémente réellement le comportement?
En extrayant une définition abstraite du comportement utilisé par X dans Y, illustré comme I ci-dessous, et en laissant le consommateur X utiliser une instance de cela au lieu de Y, il peut continuer à faire ce qu'il fait sans avoir à connaître les spécificités de Y.
Dans l'illustration ci-dessus, Y implémente I et X utilise une instance de I. Bien qu'il soit tout à fait possible que X utilise toujours Y, ce qui est intéressant, c'est que X ne le sait pas. Il sait juste qu'il utilise quelque chose qui implémente I.
Lisez l'article pour plus d'informations et une description des avantages tels que:
...
Je comprends que la réponse a déjà été donnée ici. Mais je pense toujours que certains principes de base de l'inversion de contrôle doivent être discutés ici en détail pour les futurs lecteurs.
L'inversion de contrôle (IoC) a été construite sur un principe très simple appelé Hollywood Principle . Et ça dit que,
Ne nous appelez pas, nous vous appellerons
Ce que cela signifie, c'est de ne pas aller à Hollywood pour réaliser votre rêve plutôt que si vous en êtes digne, alors Hollywood vous trouvera et réalisera votre rêve. À peu près inversé, hein?
Maintenant, quand nous discutons du principe de l'IoC, nous oublions Hollywood. Pour IoC, il doit y avoir trois éléments, un Hollywood, vous et une tâche comme réaliser votre rêve.
Dans notre monde de programmation, Hollywood représente un cadre générique (peut être écrit par vous ou quelqu'un d'autre), vous représentez le code utilisateur que vous avez écrit et la tâche représente la chose que vous voulez accomplir avec votre code. Maintenant, vous n'allez jamais déclencher votre tâche par vous-même, pas en IoC! Vous avez plutôt tout conçu de telle sorte que votre framework déclenche votre tâche pour vous. Ainsi, vous avez construit un cadre réutilisable qui peut faire de quelqu'un un héros ou un autre un méchant. Mais ce cadre est toujours en charge, il sait quand choisir quelqu'un et que quelqu'un ne sait que ce qu'il veut être.
Un exemple concret serait donné ici. Supposons que vous souhaitiez développer une application Web. Ainsi, vous créez un cadre qui gérera toutes les choses courantes qu'une application Web devrait gérer comme la gestion des requêtes http, la création de menu d'application, la diffusion de pages, la gestion des cookies, le déclenchement d'événements, etc.
Et ensuite, vous laissez des crochets dans votre cadre où vous pouvez mettre d'autres codes pour générer un menu personnalisé, des pages, des cookies ou enregistrer certains événements utilisateur, etc. au navigateur.
Donc, l'idée est assez simple. Plutôt que de créer une application utilisateur qui contrôlera tout, vous créez d'abord un cadre réutilisable qui contrôlera tout, puis écrivez vos codes personnalisés et les raccordez au cadre pour les exécuter à temps.
Laravel et EJB sont des exemples de tels cadres.
Référence:
Programmation parlant
IoC en termes simples: c'est l'utilisation d'Interface comme moyen de quelque chose de spécifique (un tel champ ou un paramètre) en tant que caractère générique qui peut être utilisé par certaines classes. Il permet la réutilisation du code.
Par exemple, disons que nous avons deux classes: chien et chat . Les deux partagent les mêmes qualités / états: âge, taille, poids. Ainsi, au lieu de créer une classe de service appelée DogService et CatService , je peux en créer une seule appelée AnimalService qui permet d'utiliser Dog et Cat uniquement s'ils utilisent l'interface IAnimal .
Cependant, de façon pragmatique, il en a en arrière.
a) La plupart des développeurs ne savent pas comment l'utiliser . Par exemple, je peux créer une classe appelée Customer et je peux créer automatiquement (à l'aide des outils de l'EDI) une interface appelée ICustomer . Il n'est donc pas rare de trouver un dossier rempli de classes et d'interfaces, que les interfaces soient réutilisées ou non. Ça s'appelle BLOATED. Certaines personnes pourraient soutenir que "peut-être à l'avenir, nous pourrions l'utiliser". : - |
b) Il a quelques limites. Par exemple, parlons du cas de Dog and Cat et je veux ajouter un nouveau service (fonctionnalité) uniquement pour les chiens. Disons que je veux calculer le nombre de jours dont j'ai besoin pour former un chien ( trainDays()
), pour le chat c'est inutile, les chats ne peuvent pas être dressés (je plaisante).
b.1) Si j'ajoute trainDays()
au Service AnimalService, cela fonctionne également avec les chats et ce n'est pas valable du tout.
b.2) Je peux ajouter une condition dans trainDays()
laquelle il évalue quelle classe est utilisée. Mais cela brisera complètement l'IoC.
b.3) Je peux créer une nouvelle classe de service appelée DogService juste pour la nouvelle fonctionnalité. Mais, cela augmentera la maintenabilité du code car nous aurons deux classes de service (avec des fonctionnalités similaires) pour Dog et c'est mauvais.
J'ai lu beaucoup de réponses pour cela, mais si quelqu'un est toujours confus et a besoin d'un "terme profane" ultra pour expliquer l'IoC, voici ma position:
Imaginez un parent et un enfant qui se parlent.
Sans IoC:
*Parent : Vous ne pouvez parler que lorsque je vous pose des questions et vous ne pouvez agir que lorsque je vous donne la permission.
Parent : Cela signifie que vous ne pouvez pas me demander si vous pouvez manger, jouer, aller aux toilettes ou même dormir si je ne vous le demande pas.
Parent : Voulez-vous manger?
Enfant : Non.
Parent : D'accord, je reviens. Attends-moi.
Enfant : (Veut jouer mais puisqu'il n'y a pas de question du parent, l'enfant ne peut rien faire).
Après 1 heure...
Parent : je suis de retour. Tu veux jouer?
Enfant : oui.
Parent : Permission accordée.
Enfant : (enfin capable de jouer).
Ce scénario simple explique que le contrôle est centré sur le parent. La liberté de l'enfant est limitée et dépend fortement de la question des parents. L'enfant peut SEULEMENT parler lorsqu'il lui est demandé de parler, et peut SEULEMENT agir sur autorisation.
Avec IoC:
L'enfant a désormais la possibilité de poser des questions et le parent peut répondre avec des réponses et des autorisations. Signifie simplement que le contrôle est inversé! L'enfant est maintenant libre de poser des questions à tout moment et bien qu'il y ait toujours une dépendance avec le parent concernant les autorisations, il n'est pas dépendant des moyens de parler / de poser des questions.
D'une manière technologique d'expliquer, cela est très similaire à l'interaction console / shell / cmd vs GUI. (Qui est la réponse de Mark Harrison au-dessus de la réponse n ° 2). Dans la console, vous dépendez de ce qui vous est demandé / affiché et vous ne pouvez pas accéder à d'autres menus et fonctionnalités sans répondre d'abord à la question; suivant un flux séquentiel strict. (par programmation, c'est comme une boucle méthode / fonction). Cependant, avec l'interface graphique, les menus et les fonctionnalités sont présentés et l'utilisateur peut sélectionner tout ce dont il a besoin, ayant ainsi plus de contrôle et étant moins restreint. (par programmation, les menus sont rappelés lorsqu'ils sont sélectionnés et une action a lieu).
L'inversion du contrôle consiste à transférer le contrôle de la bibliothèque au client. Cela a plus de sens lorsque nous parlons d'un client qui injecte (passe) une valeur de fonction (expression lambda) dans une fonction d'ordre supérieur (fonction de bibliothèque) qui contrôle (modifie) le comportement de la fonction de bibliothèque. Un client ou un framework qui injecte des dépendances de bibliothèque (qui ont un comportement) dans les bibliothèques peut également être considéré comme IoC
Étant donné qu'il existe déjà de nombreuses réponses à la question, mais qu'aucune d'entre elles ne montre la ventilation du terme de contrôle d'inversion, je vois une occasion de donner une réponse plus concise et utile.
L'inversion de contrôle est un modèle qui met en œuvre le principe d'inversion de dépendance (DIP). DIP indique ce qui suit: 1. Les modules de haut niveau ne doivent pas dépendre de modules de bas niveau. Les deux devraient dépendre d'abstractions (par exemple des interfaces). 2. Les abstractions ne devraient pas dépendre des détails. Les détails (implémentations concrètes) doivent dépendre des abstractions.
Il existe trois types d'inversion de contrôle:
Les fournisseurs d' inversion d'interface ne doivent pas définir d'interface. Au lieu de cela, le consommateur doit définir l'interface et les fournisseurs doivent la mettre en œuvre. L'interface d'inversion permet d'éliminer la nécessité de modifier le consommateur à chaque fois qu'un nouveau fournisseur s'ajoute.
Inversion de flux Change le contrôle du flux. Par exemple, vous avez une application console dans laquelle vous avez demandé d'entrer de nombreux paramètres et après chaque paramètre entré, vous êtes obligé d'appuyer sur Entrée. Vous pouvez appliquer Flow Inversion ici et implémenter une application de bureau où l'utilisateur peut choisir la séquence de saisie des paramètres, l'utilisateur peut modifier les paramètres et à la dernière étape, l'utilisateur doit appuyer sur Entrée une seule fois.
Inversion de création Elle peut être implémentée par les modèles suivants: modèle d'usine, localisateur de service et injection de dépendances. L'inversion de création permet d'éliminer les dépendances entre les types en déplaçant le processus de création d'objets de dépendance en dehors du type qui utilise ces objets de dépendance. Pourquoi les dépendances sont mauvaises? Voici quelques exemples: la création directe d'un nouvel objet dans votre code rend les tests plus difficiles; il est impossible de modifier les références dans les assemblys sans recompilation (violation du principe OCP); vous ne pouvez pas facilement remplacer une interface utilisateur de bureau par une interface utilisateur Web.
Donc, numéro 1 ci-dessus . Qu'est-ce que l'inversion de contrôle?
L'entretien est la première chose qu'il résout pour moi. Cela garantit que j'utilise des interfaces afin que deux classes ne soient pas intimes l'une avec l'autre.
En utilisant un conteneur comme Castle Windsor, il résout encore mieux les problèmes de maintenance. Pouvoir échanger un composant qui va dans une base de données contre un composant qui utilise la persistance basée sur les fichiers sans changer une ligne de code est génial (changement de configuration, vous avez terminé).
Et une fois que vous entrez dans les génériques, c'est encore mieux. Imaginez avoir un éditeur de messages qui reçoit des enregistrements et publie des messages. Peu importe ce qu'il publie, mais il a besoin d'un mappeur pour prendre quelque chose d'un enregistrement à un message.
public class MessagePublisher<RECORD,MESSAGE>
{
public MessagePublisher(IMapper<RECORD,MESSAGE> mapper,IRemoteEndpoint endPointToSendTo)
{
//setup
}
}
Je l'ai écrit une fois, mais maintenant je peux injecter de nombreux types dans cet ensemble de code si je publie différents types de messages. Je peux également écrire des mappeurs qui prennent un enregistrement du même type et les mappent à différents messages. L'utilisation de DI avec des génériques m'a donné la possibilité d'écrire très peu de code pour accomplir de nombreuses tâches.
Oh oui, il y a des problèmes de testabilité, mais ils sont secondaires par rapport aux avantages de l'IoC / DI.
J'adore vraiment l'IoC / DI.
3. Il devient plus approprié dès que vous avez un projet de taille moyenne, un peu plus complexe. Je dirais que cela devient approprié dès que vous ressentez de la douleur.
La création d'un objet au sein d'une classe est appelée couplage étroit, Spring supprime cette dépendance en suivant un modèle de conception (DI / IOC). Dans quel objet de classe est passé dans constructeur plutôt que de créer en classe. De plus, nous donnons une variable de référence de super classe dans le constructeur pour définir une structure plus générale.