Skip to content
This repository has been archived by the owner on Nov 23, 2020. It is now read-only.

Injection de Dépendance

Axel Le Bot edited this page Mar 21, 2017 · 5 revisions

Pourquoi l'injection de dependance ?

La première chose (et même la plus importante) que nous devrions savoir à ce sujet est qu'elle existe depuis longtemps et utilise le principe de l'Inversion du Contrôle, qui stipule que le flux de votre application dépend du graphe d'objet qui est construit au cours du programme Exécution, et un tel écoulement dynamique est rendu possible par des interactions d'objet étant définies par des abstractions. Cette liaison d'exécution est obtenue par des mécanismes tels que l'injection de dépendance ou un localisateur de service.

Dit que nous pouvons arriver à la conclusion que l'injection de dépendance nous apporte des avantages importants:

  • Puisque les dépendances peuvent être injectées et configurées extérieurement, nous pouvons réutiliser ces composants.
  • En injectant des abstractions en tant que collaborateurs, nous pouvons simplement changer l'implémentation de n'importe quel objet sans avoir à faire beaucoup de changements dans notre codebase, puisque cette instanciation d'objet réside dans un endroit isolé et découplé.
  • Les dépendances peuvent être injectées dans un composant: il est possible d'injecter des implémentations simulées de ces dépendances ce qui rend le test plus facile.

Une chose que nous allons voir est que nous pouvons gérer la portée de nos instances créées, ce qui est quelque chose de vraiment cool et de mon point de vue, tout objet ou collaborateur dans votre application ne devrait pas savoir quoi que ce soit sur la création des instances et le cycle de vie et cela devrait être gérés par notre framework d'injection de dépendances.

Qu'est-ce que JSR-330?

Basiquement l'injection de dépendance pour Java définit un ensemble standard d'annotations (et une interface) pour une utilisation sur les classes injectables afin de maximiser la réutilisabilité, la testabilité et la maintenabilité du code java. Les deux Dagger 1 et 2 (également Guice) sont basés sur cette norme qui apporte la cohérence et une façon standard de faire l'injection de dépendance.

Dagger 1

Je serai très rapide ici parce que cette version est hors de l'objet de cet article. Quoi qu'il en soit, Dagger 1 a beaucoup à offrir et je dirais que de nos jours est l'injecteur de dépendance le plus populaire utilisé sur Android. Il a été créé par Square inspiré de Guice.

Ses fondamentaux sont:

  • Points d'injection multiples: dépendances, en cours d'injection.
  • Fixations multiples: dépendances fournies.
  • Plusieurs modules: une collection de liaisons qui implémentent une fonctionnalité.
  • Graphes d'objets multiples: une collection de modules qui implémentent une portée.

Dagger 1 utilise le temps de compilation pour calculer les liaisons mais utilise également la réflexion et, bien qu'il ne soit pas utilisé pour instancier les objets, il est utilisé pour la composition du graphe. Tout ce processus se produit au moment de l'exécution, où Dagger tente de comprendre comment tout s'accorde, il y a donc un prix à payer: l'inefficacité parfois et les difficultés lors du débogage.

Dagger 2

Dagger 2 est un fork de Dagger 1 sous le développement lourd de Google, actuellement la version 2.0. Il a été inspiré par le projet AutoValue (https://github.com/google/auto, utile si vous êtes fatigué d'écrire des méthodes égales et hashcode partout). Dès le début, l'idée de base derrière Dagger 2, était de rendre les problèmes solvable en utilisant la génération de code, le code écrit à la main, comme si nous écrivons tout le code qui crée et fournit nos dépendances nous-mêmes.

Si nous comparons cette version avec son prédécesseur, les deux sont assez similaires dans de nombreux aspects, mais il ya aussi des différences importantes qui méritent d'être mentionnés:

  • Pas de réflexion du tout: validation de graphes, configurations et préconditions au moment de la compilation.
  • Débogage facile et entièrement traçable: pile d'appels entièrement concrète pour la fourniture et la création.
  • Plus de performance: selon google ils ont gagné 13% de la performance du processeur.
  • Obscurcissement du code: il utilise la méthode d'expédition, comme le code écrit à la main. Bien sûr, toutes ces fonctionnalités cool viennent avec un prix, ce qui le rend moins flexible: par exemple, il n'ya pas de dynamisme en raison de l'absence de réflexion.

Détails

Pour comprendre Dagger 2 il est important (et probablement un peu dur au début) de connaître les fondements de l'injection de dépendance et les concepts de chacun de ces types :

  • @Inject: Fondamentalement avec cette annotation nous demandons des dépendances. En d'autres termes, vous l'utilisez pour dire à Dagger que la classe annotée ou le champ veut participer à l'injection de dépendance. Ainsi, Dagger construira des instances de ces classes annotées et satisfera leurs dépendances.

  • @Module: Les modules sont des classes dont les méthodes fournissent des dépendances, donc nous définissons une classe et l'annotons avec @Module, ainsi, Dagger saura où trouver les dépendances afin de les satisfaire lors de la construction d'instances de classe. Une caractéristique importante des modules est qu'ils ont été conçus pour être partitionnés et composés ensemble (par exemple, nous verrons que dans nos applications, nous pouvons avoir plusieurs modules composés).

  • @Provide: Dans les modules internes, nous définissons des méthodes contenant cette annotation qui indique à Dagger comment nous voulons construire et fournir ces dépendances mentionnées.

  • @Component: Les composants sont essentiellement des injecteurs, disons un pont entre @Inject et @Module, dont sa principale responsabilité est de mettre les deux ensemble. Ils vous donnent juste des exemples de tous les types que vous avez définis, par exemple, nous devons annoter une interface avec @Component et énumérer tous les @Modules qui composeront ce composant, et si l'un d'entre eux est manquant, nous obtenons des erreurs à la compilation. Tous les composants sont conscients de la portée des dépendances qu'elle fournit via ses modules.

  • @Scope: Les scopes sont très utiles et Dagger 2 a un moyen plus concret de faire le cadre à travers des annotations personnalisées. Nous verrons un exemple plus loin, mais c'est une fonctionnalité très puissante car, comme indiqué précédemment, il n'est pas nécessaire que chaque objet sache comment gérer ses propres instances. Un exemple de cadre serait une classe avec une annotation personnalisée @PerActivity, donc cet objet vivra tant que notre Activité est en vie. En d'autres termes, nous pouvons définir la granularité de nos cadres (@PerFragment, @PerUser, etc.).

  • @Qualifier: Nous utilisons cette annotation lorsque le type de classe est insuffisant pour identifier une dépendance. Par exemple dans le cas d'Android, plusieurs fois nous avons besoin de différents types de contexte, donc nous pouvons définir une annotation de qualificatif "@ForApplication" et "@ForActivity", donc lors de l'injection d'un contexte nous pouvons utiliser ces qualificatifs pour dire à Dagger quel type de Contexte que nous voulons être fournis.