我有点懒,过去几乎完全使用现场注入。我只是提供空的构造函数,放入我的 @Inject 字段,我的一切看起来都很好很简单。然而,字段注入有其权衡,因此我设计了一些简单的规则来帮助我决定何时使用字段以及何时使用构造函数注入。如果我的逻辑有错误或者您有其他注意事项需要添加,我将不胜感激。
首先进行一些澄清,以便在同一页面上:
构造函数注入:
@Inject
public SomeClass(@Named("app version") String appVersion,
AppPrefs appPrefs) {...
与现场注入相同:
public class SomeClass {
@Inject
@Named("app version") String mAppVersion;
@Inject
AppPrefs appPrefs;
规则 1:如果我不控制对象的创建,则必须使用字段注入(想想 Android 中的 Activity 或 Fragment)。如果某些(非匕首感知)框架正在创建我的对象并为我处理它,我别无选择,只能在收到实例后手动注入它。
规则 2:如果该类在/可能在另一个不使用 Dagger 2 的项目中使用,则必须使用构造函数注入。如果其他项目不使用 Dagger,它们就无法使用 DI,因此用户必须使用“旧”方式创建对象new
.
规则 3:在使用类层次结构时首选构造函数注入,因为创建单元测试更容易。
澄清:
考虑以下使用字段注入的结构:
package superclass;
public class SuperClass {
@Inject
HttpClient mHttpClient;
...
}
.
package differentpackage;
public class SubClass extends SuperClass {
public SubClass() {
}
}
当我为以下内容创建单元测试时SubClass
在目录中test/java/differentpackage
我别无选择,只能启动整个 DI 基础设施,以便能够注入HttpClient
。相反,如果我使用这样的构造函数注入:
public class SuperClass {
private final HttpClient mHttpClient;
@Inject
public SuperClass(HttpClient httpClient) {
mHttpClient = httpClient;
}
}
在我的单元测试中我可以简单地:
HttpClient mockHttp = mock(HttpClient.class);
Subclass tested = new Subclass(mockHttp);
// tests
所以基本上现在我处于另一个极端:我倾向于主要依赖构造函数注入,并且仅在“规则 1”适用时才使用字段注入。
我在构造函数注入方面遇到的唯一“问题”是,对于“最终”类,构造函数有时会变得参数超载,并且它们看起来冗长且丑陋,如下所示:
@Inject
public ModelMainImpl(@Named("app version") String appVersion,
AppPrefs appPrefs,
LoginPrefs loginPrefs,
@ForApplication Context appContext,
NetworkInfoProvider networkInfoProvider,
AndroidEventPoster androidEventPoster,
Session session,
ForgeExchangeManager exchangeManager,
HttpFunctionality httpFunctionality,
@Named("base url") String baseUrl,
@Named("forge result producer") ResultProducer<ForgeExchangeResult> resultProducer
) {
伙计们,在构造函数注入和字段注入之间选择的规则是什么?我遗漏了一些东西,我的逻辑有问题吗?