假设我正在制造一辆汽车,我有几个不同实施的刹车豆
class Car {
@Inject
Car(@BrakeType(value="abs")Brake frontBrake, @BrakeType(value="nonabs")Brake rearBrake) { }
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface BrakeType {
String value();
}
interface Brake {}
@BrakeType(value="abs")
class AbsBrakeImpl implements Brake {
@Inject AbsBrakeImpl() {}
}
@BrakeType(value="nonabs")
class BrakeImpl implements Brake {
@Inject BrakeImpl() {}
}
为什么我的CarModule必须为特定的制动类型定义@Provides?自定义注释类型@BrakeType不应该足以确定要注入哪个impl?或者这需要使用反射,dagger2不使用?
@Module
public class CarModule {
@Provides @BrakeType("abs")
public Brake absBrake() {
return new AbsBrakeImpl();
}
@Provides @BrakeType("nonabs")
public Brake nonabsBrake() {
return new BrakeImpl();
}
}
Dagger不会在类上查看限定符注释,只能查看@Provides
或@Binds
方法。所以你班上的@BrakeType(value="abs")
注释没有任何效果。
编写代码的更规范的方法是:
class AbsBrakeImpl implements Brake {
@Inject AbsBrakeImpl() {}
}
class BrakeImpl implements Brake {
@Inject BrakeImpl() {}
}
@Module
abstract class CarModule {
@Binds @BrakeType("abs")
abstract Brake absBrake(AbsBrakeImpl impl);
@Binds @BrakeType("nonabs")
abstract Brake nonabsBrake(BrakeImpl impl);
}
请注意,由于您在实现的构造函数上有@Inject
,因此您可以简单地使用Dagger的@Bind
将实现直接绑定到适当的限定接口。
对于记录,您可以使用自己的限定符注释(作为BrakeType),或者只使用Dagger中的@Named。使用最后一个,您的代码将类似于:
@Inject @Named("abs") Brake frontBrake;
@Inject @Named("nonabs") Brake rearBrake;
在你的模块上:
@Provides @Named("abs") static Brake provideAbsBrake() {
return new AbsBrakeImpl();
}
@Provides @Named("nonabs") static Brake provideNonAbsBrake() {
return new BrakeImpl();
}
请记住使用Dagger名称约定(如提供前缀)来获取大部分内容。在你的模块上尝试使用所有@Provides方法静态,这样做结果实现不需要实例化它。
简而言之,提供和限定符一起工作,因此您需要两者。
资料来源:Dagger users guide。
@Inject constructor
意味着提供类本身,在你的情况下,这意味着你提供AbsBrakeImpl
类型和BrakeImpl
类型,所以当你尝试注入Brake
时,匕首无法找到提供者。
@Inject constructor
中的限定符不起作用,因为类类型是唯一的,我们不需要添加限定符。
所以,在你的情况下,或者你必须使用CarModule
明确地告诉Dagger,或者改变你的构造函数
class Car {
@Inject
Car(AbsBrakeImpl frontBrake, BrakeImpl rearBrake) { }
}
反思可能不是一个大问题,因为它会在编译时发生。
我没有查看source code,但是dagger只是一个注释处理器 - 只要使用一组给定的注释,它就会被调用。虽然单凭限定符可能足以找出你的意图,但我可以想到以下原因,为什么这不是最好的解决方案。
javax.inject.Qualifier
是更大的API的一部分,也可能在不同的上下文中被其他库使用。所以你可能不希望匕首为方法生成代码,只是因为它是用限定符注释的。
另一个原因可能是因为有可能创建自定义限定符,dagger必须检查每个模块中每个方法的每个注释,然后依次确定该注释本身是否用@Qualifier
注释,以查看该方法是否有一些兴趣它。这是一个不必要的开销。
可能有更多的原因,但这里列出的2个似乎足以让匕首用户使用某种合同:@Provides
。
注释不会影响代码的性能,并且具有额外的注释不会造成任何伤害,因此通过以它们的方式处理它而获得的收益远远超过丢失。