sans injection de dépendance
dans L’exemple Java suivant, la classe Client contient une variable Service member initialisée par le constructeur Client. Le client contrôle quelle implémentation de service est utilisée et contrôle sa construction. Dans cette situation, on dit que le client a une dépendance codée en dur sur ExampleService.
// An example without dependency injectionpublic class Client { // Internal reference to the service used by this client private ExampleService service; // Constructor Client() { // Specify a specific implementation in the constructor instead of using dependency injection service = new ExampleService(); } // Method within this client that uses the services public String greet() { return "Hello " + service.getName(); }}
l’injection de dépendance est une technique alternative pour initialiser la variable membre plutôt que de créer explicitement un objet service comme indiqué ci-dessus., Nous pouvons ajuster cet exemple en utilisant les différentes techniques décrites et illustrées dans les sous-sections ci-dessous.
types de dependency injectionEdit
Il existe au moins trois façons pour un objet client de recevoir une référence à un module externe:
injection de constructeur les dépendances sont fournies par le constructeur de classe d’un client. injection de setter le client expose une méthode de setter que l’injecteur utilise pour injecter la dépendance. injection d’interface l’interface de la dépendance fournit une méthode d’injecteur qui injectera la dépendance dans n’importe quel client qui lui est passé., Les Clients doivent implémenter une interface qui expose une méthode setter qui accepte la dépendance.
autres typesEdit
Il est possible pour les frameworks DI d’avoir d’autres types d’injection que ceux présentés ci-dessus.
les frameworks de test peuvent également utiliser d’autres types. Certains frameworks de test modernes n’exigent même pas que les clients acceptent activement l’injection de dépendances, rendant ainsi le code hérité testable. En particulier, dans le langage Java, il est possible d’utiliser la réflexion pour rendre publics les attributs privés lors des tests et ainsi accepter les injections par affectation.,
certaines tentatives d’Inversion de contrôle ne permettent pas de supprimer complètement la dépendance, mais remplacent simplement une forme de dépendance par une autre. En règle générale, si un programmeur ne peut regarder que le code client et dire quel framework est utilisé, alors le client a une dépendance codée en dur sur le framework.
Constructor injectionEdit
Cette méthode nécessite que le client fournisse un paramètre dans un constructeur pour la dépendance.
setter injectionEdit
Cette méthode nécessite que le client fournisse une méthode setter pour la dépendance.,
interface injectionEdit
Il s’agit simplement du client publiant une interface de rôle sur les méthodes setter des dépendances du client. Il peut être utilisé pour établir comment l’injecteur doit parler au client lors de l’injection de dépendances.
// Service setter interface.public interface ServiceSetter { public void setService(Service service);}// Client classpublic class Client implements ServiceSetter { // Internal reference to the service used by this client. private Service service; // Set the service that this client is to use. @Override public void setService(Service service) { this.service = service; }}
injection du constructeur comparisonEdit
préféré lorsque toutes les dépendances peuvent être construites en premier car il peut être utilisé pour s’assurer que l’objet client est toujours dans un état valide, par opposition à ce que certaines de ses références de dépendance soient null (ne, Cependant, à lui seul, il manque de flexibilité pour que ses dépendances changent plus tard. Cela peut être une première étape pour rendre le client immuable et donc thread sûr.
setter injection comparisonEdit
nécessite que le client fournisse une méthode setter pour chaque dépendance. Cela donne la liberté de manipuler l’état des références de dépendance à tout moment. Cela offre de la flexibilité, mais s’il y a plus d’une dépendance à injecter, il est difficile pour le client de s’assurer que toutes les dépendances sont injectées avant que le client puisse être utilisé.,
étant donné que ces injections se produisent indépendamment, il n’y a aucun moyen de dire quand l’injecteur a fini de câbler le client. Une dépendance peut être laissée nulle simplement par l’injecteur qui n’appelle pas son setter. Cela oblige à vérifier que l’injection a été effectuée à partir du moment où le client est assemblé jusqu’à chaque fois qu’il est utilisé.
Interface injection comparisonEdit
l’avantage de l’injection d’interface est que les dépendances peuvent ignorer complètement leurs clients tout en pouvant toujours recevoir une référence à un nouveau client et, en l’utilisant, renvoyer une référence à soi au client., De cette façon, les dépendances deviennent des injecteurs. La clé est que la méthode d’injection (qui pourrait simplement être une méthode de setter classique) est fournie via une interface.
un assembleur est toujours nécessaire pour introduire le client et ses dépendances. L’assembleur prendrait une référence au client, la convertisserait en interface setter qui définit cette dépendance et la transmettrait à cet objet de dépendance qui se retournerait et transmettrait une référence à soi au client.,
pour que l’injection d’interface ait une valeur, la dépendance doit faire quelque chose en plus de simplement renvoyer une référence à elle-même. Cela pourrait agir en tant qu’usine ou sous-assembleur pour résoudre d’autres dépendances, abstrayant ainsi certains détails de l’assembleur principal. Il pourrait s’agir d’un comptage de référence afin que la dépendance sache combien de clients l’utilisent. Si la dépendance maintient une collection de clients, elle pourrait ensuite les injecter tous avec une instance différente d’elle-même.,
Assembling examplesEdit
l’assemblage manuel dans main à la main est un moyen d’implémenter l’injection de dépendances.
l’exemple ci-dessus construit le graphe objet manuellement, puis l’appelle à un moment donné pour le démarrer. Il est Important de noter que cet injecteur n’est pas pur. Il utilise l’un des objets qu’il construit. Il a une relation purement de construction avec ExampleService mais mélange la construction et l’utilisation du Client. Cela ne devrait pas être commun. Elle est cependant inévitable., Tout comme un logiciel orienté objet a besoin d’une méthode statique non orientée objet comme main() pour démarrer, un graphe d’objet injecté par dépendance a besoin d’au moins un (de préférence un seul) point d’entrée pour démarrer le tout.
la construction manuelle dans la méthode principale peut ne pas être aussi simple et peut impliquer d’appeler des constructeurs, des usines ou d’autres modèles de construction. Cela peut être assez avancé et abstrait., La ligne est franchie de l’injection manuelle de dépendance à l’injection de dépendance du framework une fois que le code de construction n’est plus personnalisé pour l’application et est plutôt universel.
des Frameworks comme Spring peuvent construire ces mêmes objets et les connecter ensemble avant de renvoyer une référence au client. Toute mention de l’exemple bétonservice peut être déplacé du code vers les données de configuration.
les Frameworks comme Spring permettent d’externaliser les détails de l’assemblage dans les fichiers de configuration.Ce code (ci-dessus) construit des objets et les relie ensemble en fonction des Beans.xml (ci-dessous)., ExampleService est toujours construit même s’il n’est mentionné que ci-dessous. Un graphe d’objet long et complexe peut être défini de cette façon et la seule classe mentionnée dans le code serait celle avec la méthode du point d’entrée, qui dans ce cas est greet().
dans l’exemple ci-dessus, le Client et le Service n’ont pas eu à subir de changements à fournir D’ici le printemps. Ils sont autorisés à rester de simples POJOs. Cela montre comment Spring peut connecter des services et des clients qui ignorent complètement son existence. Cela ne pourrait pas être dit si des annotations Spring étaient ajoutées aux classes., En empêchant les annotations et les appels spécifiques à Spring de s’étaler entre de nombreuses classes, le système ne dépend que vaguement de Spring. Cela peut être important si le système a l’intention de survivre au printemps.
le choix de garder les POJOs purs n’est pas gratuit. Plutôt que de dépenser l’effort pour développer et maintenir des fichiers de configuration complexes, il est possible d’utiliser simplement des annotations pour marquer les classes et laisser Spring faire le reste du travail. La résolution des dépendances peut être simple si elles suivent une convention telle que la correspondance par type ou par nom. C’est choisir la convention sur la configuration., On peut également soutenir que, lors de la refactorisation vers un autre framework, la suppression des annotations spécifiques au framework serait une partie triviale de la tâche et de nombreuses annotations d’injection sont maintenant standardisées.
@Componentpublic class ExampleService { public String getName() { return "World!"; }}
Assembly comparisonEdit
Les différentes implémentations d’injecteur (usines, localisateurs de service et conteneurs d’injection de dépendance) ne sont pas si différentes en ce qui concerne l’injection de dépendance. Ce qui fait toute la différence, c’est où ils sont autorisés à être utilisés., Déplacer les appels vers une usine ou un localisateur de service hors du client et dans main et soudainement main fait un conteneur d’injection de dépendance assez bon.
en déplaçant toutes les connaissances de l’injecteur, un client propre, libre de toute connaissance du monde extérieur, est laissé pour compte. Cependant, tout objet qui utilise d’autres objets peut être considéré comme un client. L’objet qui contient main ne fait pas exception. Cet objet principal n’utilise pas l’injection de dépendance. Il utilise en fait le modèle de localisateur de service. Cela ne peut être évité car le choix des implémentations de service doit être fait quelque part.,
L’externalisation des dépendances dans les fichiers de configuration ne change pas ce fait. Ce qui fait de cette réalité une partie d’une bonne conception, c’est que le Localisateur de service n’est pas réparti dans toute la base de code. Il est limité à un seul endroit par application. Cela laisse le reste de la base de code libre d’utiliser l’injection de dépendance pour créer des clients propres.
modèle D’Injection de dépendance
Les exemples jusqu’à présent étaient des exemples trop simples sur la construction d’une chaîne., Cependant, le modèle d’injection de dépendance est plus utile lors de la construction d’un graphique d’objet où les objets communiquent via des messages. Les objets construits en main dureront toute la durée de vie du programme. Le modèle typique consiste à construire le graphique, puis à appeler une méthode sur un objet pour envoyer le flux de contrôle dans le graphique d’objet. Tout comme main est le point d’entrée du code statique, cette méthode est le point d’entrée du code non statique des applications.,
AngularJS exampleeedit
dans le framework AngularJS, il n’y a que trois façons pour un composant (objet ou fonction) d’accéder directement à ses dépendances:
- Le composant peut créer la dépendance, en utilisant généralement l’opérateur
new
. - Le composant peut rechercher la dépendance, en se référant à une variable globale.
- Le composant peut avoir la dépendance transmise là où elle est nécessaire.
Les deux premières options de création ou de recherche de dépendances ne sont pas optimales car elles codent en dur la dépendance au composant., Cela rend difficile, voire impossible, de modifier les dépendances. Ceci est particulièrement problématique dans les tests, où il est souvent souhaitable de fournir des dépendances simulées pour l’isolation des tests.
la troisième option est la plus viable, car elle supprime la responsabilité de localiser la dépendance du composant. La dépendance est simplement remise au composant.
dans l’exemple ci-dessus, SomeClass
n’est pas concerné par la création ou la localisation de la dépendance greeter, il est simplement remis au greeter lorsqu’il est instancié.,
c’est souhaitable, mais cela met la responsabilité de mettre la main sur la dépendance sur le code qui construitSomeClass
.
pour gérer la responsabilité de la création de dépendances, chaque application AngularJS dispose d’un injecteur. L’injecteur est un localisateur de service est responsable de la construction et de recherche de dépendances.
Voici un exemple d’utilisation du service injecteur:
créez un nouvel injecteur qui peut fournir des composants définis dans le modulemyModule
et demandez notre service greeter à l’injecteur., (Ceci est généralement fait automatiquement par le bootstrap AngularJS).
var injector = angular.injector();var greeter = injector.get('greeter');
demander des dépendances résout le problème du codage en dur, mais cela signifie également que l’injecteur doit être transmis dans toute l’application. Le passage de l’injecteur enfreint la Loi de Demeter., Pour remédier à cela, nous utilisons une notation déclarative dans nos modèles HTML, pour confier la responsabilité de la création de composants à l’injecteur, comme dans cet exemple:
<div ng-controller="MyController"> <button ng-click="sayHello()">Hello</button></div>
function MyController($scope, greeter) { $scope.sayHello = function() { greeter.greet('Hello World'); };}
lorsque AngularJS compile le code HTML, il traite le ng-controller
directive, qui à son tour demande à l’injecteur de créer une instance du contrôleur et de ses dépendances.
injector.instantiate(MyController);
Ceci est fait dans les coulisses., Étant donné que ng-controller
s’en remet à l’injecteur pour instancier la classe, il peut satisfaire toutes les dépendances de MyController
sans que le contrôleur ne connaisse jamais l’injecteur. Le code de l’application déclare simplement les dépendances dont il a besoin, sans avoir à traiter avec l’injecteur. Cette configuration ne viole pas la Loi de Demeter.
C#Edit
Exemple du Constructeur d’injection, l’injection par Mutateur et de l’Interface d’injection sur le C#