I am familiar with the dependency inversion principle in traditional design patterns, where you have an abstract product that performs tasks in a class that requests a factory method. But dependency injection is different in that it uses annotations to generate products.
I am reviewing this Dagger 2 example. This is the end result:
// CoffeeApp.java
public class CoffeeApp {
@Singleton
@Component(modules = { DripCoffeeModule.class })
public interface Coffee {
CoffeeMaker maker();
}
public static void main(String[] args) {
Coffee coffee = DaggerCoffeeApp_Coffee.builder().build();
coffee.maker().brew();
}
}
$ java -cp ... coffee.CoffeeApp
~ ~ ~ heating ~ ~ ~
=> => pumping => =>
[_]P coffee! [_]P
I'm having trouble understanding this line right here:
CoffeeMaker maker();
In the CoffeeMaker class, there is no make() method. So how does this work?
This is my understanding:
The CoffeeMaker class uses the @Inject annotation in its constructor:
@Inject CoffeeMaker(Lazy<Heater> heater, Pump pump) {
this.heater = heater;
this.pump = pump;
}
This will force Dagger to instantiate a new Heater and a new Pump whenever a CoffeeMaker is instantiated, is that correct? Or does the CoffeeMaker class itself just needs to be referenced? The document says this:
When you request a CoffeeMaker, it’ll obtain one by calling new CoffeeMaker() and setting its injectable fields.
BUt what does it mean by request?
When it says, it will set its injectable fields, I notice that Heater and Pump are interfaces. There is a corresponding PumpModule class with the @Module annotation. And it contains the method providePump
.
The document says:
The method’s return type defines which dependency it satisfies.
Does this mean that when @Inject CoffeeMaker
constructor is called, it in turn discovers the pump reference and searches for the PumpModule @Module and then discovers providePump and instantiates a new pump of type Thermosiphon?