2268 votes

Qu'est-ce que l'inversion de contrôle ?

L'inversion de contrôle (IoC) peut être assez déroutante lorsqu'on la rencontre pour la première fois.

  1. Qu'est-ce que c'est ?
  2. Quel problème résout-il ?
  3. Quand est-il approprié de l'utiliser et quand ne l'est-il pas ?

352 votes

Le problème de la plupart de ces réponses est la terminologie utilisée. Qu'est-ce qu'un conteneur ? Une inversion ? Dépendance ? Expliquez-le en termes simples, sans les grands mots.

15 votes

12 votes

Il s'agit de l'injection de dépendances (DI) - voir la description de Martin Fowlers ici : martinfowler.com/articles/injection.html#InversionOfControl

1952voto

urini Points 8233

Les modèles d'inversion de contrôle (IoC) et d'injection de dépendances (DI) ont pour but de supprimer les dépendances de votre code.

Par exemple, disons que votre application possède un composant éditeur de texte et que vous souhaitez fournir une vérification orthographique. Votre code standard ressemblerait à quelque chose comme 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 module 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 instanctions SpellChecker ( this.checker = new SpellChecker(); ), ce qui signifie que le TextEditor dépend directement de la classe SpellChecker classe.

Dans le deuxième exemple de code, nous créons une abstraction en faisant en sorte que l'élément SpellChecker classe de dépendance dans TextEditor La signature du constructeur de la classe (sans initialiser la dépendance dans la classe). Cela nous permet d'appeler la dépendance puis de la passer à la classe TextEditor comme suit :

SpellChecker sc = new SpellChecker(); // dependency
TextEditor textEditor = new TextEditor(sc);

Maintenant, le client qui crée le TextEditor a le contrôle de la classe SpellChecker à utiliser parce que nous injectons la dépendance dans l'application TextEditor signature.

66 votes

Bon exemple clair. Cependant, supposons qu'au lieu d'exiger que l'interface ISpellChecker soit transmise au constructeur de l'objet, nous l'exposions comme une propriété paramétrable (ou une méthode SetSpellChecker). Cela constituerait-il encore un IoC ?

35 votes

Chainguy1337 - oui, en effet. L'utilisation de setters comme cela est appelée injection de setter par opposition à l'injection de constructeur (les deux techniques d'injection de dépendance). IoC est un modèle assez générique, mais l'injection de dépendances permet d'obtenir IoC.

289 votes

Malgré les nombreux votes positifs, cette réponse est incorrecte. Veuillez consulter martinfowler.com/articles/injection.html#InversionOfControl . En particulier, notez la partie disant "L'inversion de contrôle est un terme trop générique, et donc les gens le trouvent confus. En conséquence, après de nombreuses discussions avec divers défenseurs de l'IoC, nous avons opté pour le nom d'injection de dépendances".

796voto

Mark Harrison Points 77152

L'inversion de contrôle est ce que vous obtenez lorsque votre programme fait des callbacks, par exemple comme un programme gui.

Par exemple, dans un menu de la vieille école, vous pourriez avoir :

print "enter your name"
read name
print "enter your address"
read address
etc...
store in database

contrôlant ainsi le flux de l'interaction avec l'utilisateur.

Dans un programme GUI ou autre, on dira plutôt :

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

Le contrôle est donc maintenant 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 saisies et le moment où elles sont enregistrées dans la base de données.

En gros, tout ce qui est avec une boucle d'événement, des callbacks ou des déclencheurs d'exécution entre dans cette catégorie.

189 votes

Ne notez pas ce type. Techniquement, il a raison. martinfowler.com/bliki/InversionOfControl.html IoC est un principe très général. Le flux de contrôle est "inversé" par l'injection de dépendances, car vous avez effectivement délégué les dépendances à un système externe (par exemple, un conteneur IoC).

44 votes

D'accord avec le commentaire de Schneider. 5 votes négatifs ? C'est à n'y rien comprendre, puisque c'est la seule réponse qui soit vraiment correcte. Notez le début : comme un programme gui.' L'injection de dépendances n'est que la réalisation la plus courante de l'IoC.

48 votes

En effet, c'est l'une des rares correct anwsers ! Les gars, IoC est pas fondamentalement sur les dépendances. Pas du tout.

497voto

ragu.pattabi Points 2711

Qu'est-ce que l'inversion de contrôle ?

Si vous suivez ces deux simples étapes, vous avez effectué une inversion de contrôle :

  1. Séparer ce que -pour faire partie de quand -à faire.
  2. Veiller à ce que quand partie connue sous le nom de petit que possible sur ce que et vice versa.

Il existe plusieurs techniques possibles pour chacune de ces étapes, en fonction de la technologie/du langage que vous utilisez pour votre mise en œuvre.

--

Le site inversion partie de l'inversion de contrôle (IoC) est la chose la plus déroutante ; parce que inversion est le terme relatif. La meilleure façon de comprendre IoC est d'oublier ce mot !

--

Exemples

  • Gestion des événements. Gestionnaires d'événements (partie "quoi faire") -- Lever des événements (partie "quand faire")
  • Injection de dépendances. Le code qui construit une dépendance (partie what-to-do) - instancie et injecte cette dépendance pour les clients lorsque cela est nécessaire, ce qui est généralement pris en charge par les outils DI tels que Dagger (partie when-to-do).
  • Interfaces. Client du composant (partie "quand faire") -- Mise en œuvre de l'interface du composant (partie "quoi faire")
  • Fixation de xUnit. Setup et TearDown (partie what-to-do) -- Les cadres xUnit appellent Setup au début et TearDown à la fin (partie when-to-do).
  • Modèle de conception de la méthode template. Méthode template when-to-do part -- mise en œuvre de la sous-classe primitive what-to-do part
  • Méthodes de conteneur de DLL dans COM. DllMain, DllCanUnload, etc (partie "quoi faire") -- COM/OS (partie "quand faire")

2 votes

Comment vous dites Interfaces. Le client du composant (partie "quand faire") car "quand" n'a pas de sens lorsque nous utilisons des interfaces (ex : injection de dépendance), nous l'abstrayons simplement et donnons au client la flexibilité d'ajouter une implémentation mais il n'y a pas de "quand" impliqué ici. Je suis d'accord avec le "quand" dans le cas de la levée d'événements du traitement des événements.

1 votes

Par "composant client", j'entends l'utilisateur/client de l'interface. Le client sait "quand" déclencher la partie "quoi faire", que l'intention soit d'étendre la fonctionnalité ou non.

1 votes

Jetez un coup d'œil à ce merveilleux article de Martin Fowler. Il montre comment les interfaces constituent la partie fondamentale de l'inversion du contrôle : martinfowler.com/articles/injection.html#InversionOfControl

108voto

ahe Points 730

Avant d'utiliser l'inversion de contrôle, vous devez être bien conscient du fait qu'elle a ses avantages et ses inconvénients et vous devez savoir pourquoi vous l'utilisez si vous le faites.

Pour :

  • Votre code est découplé afin que vous puissiez facilement échanger les implémentations d'une interface avec d'autres implémentations.
  • C'est une forte motivation pour coder contre des interfaces plutôt que des implémentations.
  • Il est très facile d'écrire des tests unitaires pour votre code car il ne dépend de rien d'autre que des objets qu'il accepte dans ses constructeurs/réglages et vous pouvez facilement les initialiser avec les bons objets en isolation.

Cons :

  • L'IoC ne se contente pas d'inverser le flux de contrôle dans votre programme, il l'assombrit aussi considérablement. Cela signifie que vous ne pouvez plus simplement lire votre code et sauter d'un endroit à l'autre, car les connexions qui se trouveraient normalement dans votre code ne sont plus dans le code. Elles se trouvent plutôt dans des fichiers de configuration XML ou des annotations et dans le code de votre conteneur IoC qui interprète ces métadonnées.
  • Il existe une nouvelle catégorie de bogues où vous vous trompez dans votre configuration XML ou vos annotations et vous pouvez passer beaucoup de temps à découvrir pourquoi votre conteneur IoC injecte une référence nulle dans l'un de vos objets dans certaines conditions.

Personnellement, je vois les points forts de l'IoC et je les apprécie vraiment, mais j'ai tendance à éviter l'IoC autant que possible parce qu'il transforme votre logiciel en une collection de classes qui ne constituent plus un "vrai" programme mais juste quelque chose qui doit être assemblé par des métadonnées de configuration ou d'annotation XML et qui tomberait (et tombe) en morceaux sans lui.

3 votes

La première affirmation est incorrecte. Idéalement, il ne devrait y avoir qu'une seule utilisation du conteneur IOC dans votre code, et c'est votre méthode principale. Tout le reste devrait descendre en cascade à partir de là

26 votes

Je pense que ce qu'il veut dire, c'est que vous ne pouvez pas simplement lire : myService.DoSomething() et aller à la définition de DoSomething, parce qu'avec IoC, myService est juste une interface, et l'implémentation réelle vous est inconnue, à moins que vous alliez la chercher dans les fichiers de configuration xml ou dans la méthode principale où votre ioc est configuré.

9 votes

C'est là que Resharper intervient - "cliquer pour aller à l'implémentation" contre l'interface. Éviter IoC (ou plus précisément DI dans votre exemple) signifie probablement aussi que vous ne testez pas correctement

78voto

NilObject Points 7874
  1. Article de Wikipedia . Pour moi, l'inversion de contrôle consiste à transformer votre code écrit de manière séquentielle et à le transformer en une structure de délégation. Au lieu que votre programme contrôle explicitement tout, votre programme met en place une classe ou une bibliothèque avec certaines fonctions à appeler lorsque certaines choses se produisent.

  2. Il résout la duplication du code. Par exemple, dans le passé, vous deviez écrire manuellement votre propre boucle d'événements, en interrogeant les bibliothèques système pour les nouveaux événements. Aujourd'hui, dans la plupart des API modernes, il vous suffit d'indiquer aux bibliothèques système les événements qui vous intéressent, et elles vous informeront lorsqu'ils se produiront.

  3. L'inversion de contrôle est un moyen pratique de réduire la duplication du code. Si vous vous retrouvez à copier une méthode entière et à ne modifier qu'une petite partie du code, vous pouvez envisager de l'aborder avec l'inversion de contrôle. L'inversion de contrôle est facilitée dans de nombreux langages par le concept de délégués, d'interfaces ou même de pointeurs de fonction bruts.

    Il n'est pas approprié de l'utiliser dans tous les cas, car le flux d'un programme peut être plus difficile à suivre lorsqu'il est écrit de cette façon. C'est une façon 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, à moins qu'elle ne résolve vraiment un problème de duplication de code.

41 votes

Je trouve que cet article de Wikipedia est très confus et a besoin d'être corrigé. Allez voir la page de discussion pour rire un peu.

2 votes

Écrire votre propre boucle d'événement pourrait encore être une inversion de contrôle, si cette boucle d'événement prend la place d'un framework et que le reste du code utilise le principe IoC, vous venez d'écrire votre propre framework. En fait, ce n'est pas une mauvaise chose, cela augmente la lisibilité au prix d'un peu plus de codage (ce qui n'est pas toujours approprié non plus).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X