官方提供了Coffee App,演示Dagger2 使用。其内容真的有些简单,下面就简单分析一下其实现过程
我们的目标是 完成Coffee 制作并打印制作过程。显然我们要定义Component返回CoffeeMaker && CoffeeLogger对象。
@Component
public interface CoffeeShop {
CoffeeMaker maker();
CoffeeLogger logger();
}
public class CoffeeMaker {
private final CoffeeLogger logger;
private final Lazy heater; // Create a possibly costly heater only when we use it.
private final Pump pump;
CoffeeMaker(CoffeeLogger logger, Lazy heater, Pump pump) {
this.logger = logger;
this.heater = heater;
this.pump = pump;
}
public void brew() {
heater.get().on();
pump.pump();
logger.log(" [_]P coffee! [_]P ");
heater.get().off();
}
}
显然,为了实现CoffeeMaker对象注入,最简单的方式在构造函数添加@Inject注解。为了符合单一原则,CoffeeMaker内部需要的CoffeeLogger、Heater、Pump都需要从外部进行注入,下面依次分析。
CoffeeLogger 工具类原始代码如下:
public final class CoffeeLogger {
private final List logs = new ArrayList<>();
CoffeeLogger() {}
public void log(String msg) {
logs.add(msg);
}
public List logs() {
return new ArrayList<>(logs);
}
}
最简单的注入方式莫过于给构造函数添加@Inject注解。
Heater接口源码如下:
public interface Heater {
void on();
void off();
boolean isHot();
}
不能直接注入接口,需要提供实现类和Module进行类型转换
public class ElectricHeater implements Heater {
private final CoffeeLogger logger;
private boolean heating;
@Inject
ElectricHeater(CoffeeLogger logger) {
this.logger = logger;
}
@Override
public void on() {
this.heating = true;
logger.log("~ ~ ~ heating ~ ~ ~");
}
@Override
public void off() {
this.heating = false;
}
@Override
public boolean isHot() {
return heating;
}
}
@Module
interface HeaterModule {
@Binds
Heater bindHeater(ElectricHeater impl);
}
给实现类构造函数添加@Inject注解,在Module下写一个@Binds修饰的函数,参数为实现类、返回值为接口。也是可以实现的最简单的方式。
为了CoffeeShop可以使用HeaterModule,将HeaterModule添加到CoffeeShop的modules参数中。
public interface Pump {
void pump();
}
public class Thermosiphon implements Pump {
private final CoffeeLogger logger;
private final Heater heater;
@Inject
Thermosiphon(CoffeeLogger logger, Heater heater) {
this.logger = logger;
this.heater = heater;
}
@Override
public void pump() {
if (heater.isHot()) {
logger.log("=> => pumping => =>");
}
}
}
@Module
abstract class PumpModule {
@Binds
abstract Pump providePump(Thermosiphon pump);
}
这个和Heater注入完全一样。
这个很好理解,Heater、Pump如果都创建一个CoffeeLogger,就不可能将日志记录完整。因此将CoffeeLogger和CoffeeShop都添加上@Singleton注解。
Thermosiphon.pump()中判断heater状态,如果不能保证单例,判断状态也没有任何意义。对于接口的实现方式,就只能在@Binds修饰的函数上进行添加。
https://dagger.dev/dev-guide/
https://gitee.com/guchuanhang/dagger2-coffee-app