À propos de Dagger2, qui est une bibliothèque DI pour Java / Android, l'exemple officiel Coffee app Je voudrais expliquer le mécanisme basé sur (/ master / examples / simple / src / main / java / coffee).
Cependant, l'application Coffee était un peu difficile à comprendre (@ Binds
, Lazy
, etc.), donc le code décrit ci-dessous a été légèrement modifié.
Le Guide de l'utilisateur Dagger2 peut être compris avec des connaissances du haut vers le milieu (Singletons et liaisons étendues).
Ce que cet exemple essaie de faire est de créer une instance de la classe CoffeeMaker avec Dagger2.
La classe CoffeeMaker a les dépendances suivantes.
https://docs.google.com/presentation/d/1fby5VeGU9CN8zjw4lAb2QPPsKRxx6mSwCe9q7ECNSJQ/pub?start=false&loop=false&delayms=3000&slide=id.p
Résoudre cette dépendance et obtenir une instance de CoffeeMaker peut être un peu délicat.
Heater heater = new ElectricHeater();
Pump pump = new Thermosiphon(heater);
CoffeeMaker coffeeMaker = new CoffeeMaker(heater, pump).maker();
coffeeMaker.brew();
En utilisant Dagger2, le code ci-dessus ressemble à ceci:
CoffeeMaker coffeeMaker = DaggerCoffeeShop.create().maker();
coffeeMaker.brew();
De cette manière, le code client CoffeeMaker est libéré de la complexité de la création de dépendances. Ce qui suit décrit comment Dagger2 crée ces dépendances.
Dagger utilise un constructeur avec l'annotation @ Inject
pour créer une instance.
class Thermosiphon implements Pump {
private final Heater heater;
@Inject
Thermosiphon(Heater heater) {
this.heater = heater;
}
@Override
public void pump() {
if (heater.isHot()) {
System.out.println("=> => pumping => =>");
}
}
}
Si une instance Thermosiphon est demandée, une instance Thermosiphon sera créée à l'aide du constructeur ci-dessus.
Ici, la classe Thermosiphon dépend de la classe Heater. Dagger identifie les dépendances définies dans le constructeur et les résout.
Dagger essaie de satisfaire la dépendance en créant une instance du type demandé, mais la déclaration de dépendance par @ Inject
ne fonctionne pas toujours.
Dans les cas suivants, «@ Inject» ne fonctionnera pas.
--Type est une interface
Dans l'application Coffee, les types dont dépend CoffeeMaker (chauffage et pompe) sont déclarés comme interfaces, ce qui est le cas ci-dessus. Dans ces cas, la méthode annotée avec «@ Provides» crée une instance.
Par exemple, Heater déclare une dépendance comme suit: Définissez une méthode annotée avec «@ Provides» et spécifiez Heater comme type de retour.
@Provides
static Heater provideHeater() {
return new ElectricHeater();
}
De même, Thermosiphon déclare:
La méthode @ Provides
peut avoir ses propres dépendances.
@Provides
static Pump providePump(Thermosiphon pump) {
return pump;
}
La méthode @ Provides
doit appartenir au module.
Un module est une classe avec l'annotation @ Module
.
@Module
class DripCoffeeModule {
@Provides
static Heater provideHeater() {
return new ElectricHeater();
}
@Provides
static Pump providePump(Thermosiphon pump) {
return pump;
}
}
Par convention, la méthode «@ Provides» semble avoir un préfixe provide et le module a un suffixe Module.
Les classes et méthodes définies par @ Inject
et @ Provides
forment un graphe de dépendance d'un objet.
Pour créer ce graphique, définissez un composant.
Un composant est une interface annotée avec @ Component
et a des méthodes sans arguments.
Le type de retour de ces méthodes sera le type que vous souhaitez résoudre.
Ce qui suit définit un composant CoffeeShop avec une méthode qui renvoie une occurrence de CoffeeMaker. Passez des modules aux composants pour créer des dépendances subordonnées. Ici, nous passons le DripCoffeeModule.
@Component(modules = DripCoffeeModule.class)
interface CoffeeShop {
CoffeeMaker maker();
}
Dagger générera automatiquement une implémentation de CoffeeShop basée sur cette définition. La classe d'implémentation générée par Dagger est préfixée par Dagger. Ici, une classe d'implémentation appelée DaggerCoffeeShop est générée.
La classe d'implémentation de composant a une méthode de générateur, qui est utilisée pour créer des dépendances.
CoffeeShop coffeeShop = DaggerCoffeeShop.builder()
.dripCoffeeModule(new DripCoffeeModule())
.build();
Dans l'exemple ci-dessus, une instance de DripCoffeeModule est créée manuellement et transmise au générateur, mais si les conditions suivantes sont remplies, ce processus est inutile.
--Si vous avez accès au constructeur par défaut du module
--Si toutes les méthodes @ Provides
du module sont statiques
Pour les composants, si tous les modules suivants s'appliquent à ce qui précède, la classe d'implémentation dispose d'une méthode de création qui vous permet de créer une instance directement sans passer par le générateur.
CoffeeShop coffeeShop = DaggerCoffeeShop.create();
Enfin, le code client CoffeeMaker ressemble à ceci:
CoffeeMaker coffeeMaker = DaggerCoffeeShop.create().maker();
coffeeMaker.brew();
Voici une version légèrement modifiée de l'application officielle du café (https://github.com/google/dagger/tree/master/examples/simple/src/main/java/coffee). Il est implémenté uniquement avec les fonctions de la plage expliquée ci-dessus.
** * Seule l'annotation @ Singleton
sera décrite plus tard. ** **
Heater.java(Restez officiel)
interface Heater {
void on();
void off();
boolean isHot();
}
Pump.java(Restez officiel)
interface Pump {
void pump();
}
ElectricHeater(Restez officiel)
class ElectricHeater implements Heater {
boolean heating;
@Override
public void on() {
System.out.println("~ ~ ~ heating ~ ~ ~");
this.heating = true;
}
@Override
public void off() {
this.heating = false;
}
@Override
public boolean isHot() {
return heating;
}
}
Thermosiphon(Restez officiel)
class Thermosiphon implements Pump {
private final Heater heater;
@Inject
Thermosiphon(Heater heater) {
this.heater = heater;
}
@Override
public void pump() {
if (heater.isHot()) {
System.out.println("=> => pumping => =>");
}
}
}
DripCoffeeModule.java
@Module
class DripCoffeeModule {
@Singleton
@Provides
static Heater provideHeater() {
return new ElectricHeater();
}
@Provides
static Pump providePump(Thermosiphon pump) {
return pump;
}
}
CoffeeMaker(Restez officiel)
class CoffeeMaker {
private final Heater heater;
private final Pump pump;
@Inject
CoffeeMaker(Heater heater, Pump pump) {
this.heater = heater;
this.pump = pump;
}
public void brew() {
heater.on();
pump.pump();
System.out.println(" [_]P coffee![_]P ");
heater.off();
}
}
CoffeeShop.java
@Singleton
@Component(modules = DripCoffeeModule.class)
public interface CoffeeShop {
CoffeeMaker maker();
}
CoffeeApp.java
public class CoffeeApp {
public static void main(String[] args) {
CoffeeMaker coffeeMaker = DaggerCoffeeShop.create().maker();
coffeeMaker.brew();
}
}
@ Singleton
Lors de la résolution des dépendances, Dagger essaiera de créer une instance du type à chaque fois qu'elle est demandée par défaut. Cependant, dans le cas de l'application Coffee, le comportement par défaut ne fonctionne pas comme prévu.
La méthode d'infusion de CoffeeMaker est d'allumer le chauffage (chauffe.on ()), de verser de l'eau (pump.pump ()), de préparer du café (println ()) et de l'éteindre à nouveau. Ne versez de l'eau que lorsque le chauffage est allumé. Vérifier si le chauffage est allumé est délégué à l'instance Heat détenue par l'instance Pump, mais à ce stade, l'instance Heat détenue par l'instance CoffeeMaker et l'instance Heat détenue par l'instance Pump sont Vous devez faire référence à la même chose.
Comme mentionné ci-dessus, Dagger est créé chaque fois qu'un type est demandé, il ne se comportera donc pas comme prévu.
Vous pouvez ensuite utiliser l'annotation @ Singleton
pour spécifier que la même instance doit toujours être renvoyée lorsque le type est demandé.
Dans le code ci-dessus, la méthode provideHeater de DripCoffeeModule est annotée avec @ Singleton
pour spécifier que l'instance Heater est singleton.
L'interface CoffeeShop est également annotée avec @ Singleton
afin que le composant et ses instances subordonnées aient le même cycle de vie.
J'ai expliqué la partie de base qui est la première étape pour comprendre Dagger. Comme ce n'est que la première partie du guide de l'utilisateur, je pense qu'il y a encore beaucoup de connaissances qui ne sont pas suffisantes pour pratiquer Dagger, mais ceux qui veulent utiliser Dagger à partir de maintenant, et les miens quelques jours plus tard. J'ai pensé que cela vous serait utile.
Recommended Posts