我有点懒惰,习惯几乎完全用场注射。我只是提供空构造函数,把我的@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:使用类层次结构时PREFER构造函数注入,因为它更容易创建单元测试。
澄清:
考虑以下使用场注入的结构:
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”适用时使用场注射。 我对构造函数注入的唯一“问题”是,对于'end'类,构造函数有时会变得非常重载参数,它们看起来像这样冗长和丑陋:
@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
) {
伙计们,你在构造函数和字段注入之间选择的规则是什么?我错过了什么,我的逻辑中有错误吗?
答案 0 :(得分:6)
使用构造函数注入。如果你不能,请使用属性注入。
规则1似乎没问题,比如你可以使用Property(field)注入的装饰或属性。
规则2似乎没问题,因为谁使用你的类他们必须遵循你的构造函数。他们可能不知道他们也必须为你的财产提供服务。
规则3它不仅适用于单元测试。应用Single Responsibilty非常有用。您可以更轻松地查看对象图。否则,您将使用属性隐藏它。
如果我们提出你的问题,是的,你的构造函数中有很多参数。但解决方案不是属性注入。您可以重构代码并使用aggregate services