Dagger 2:什么时候使用构造函数注入,什么时候使用字段注入?

Dagger 2: When to use constructor injections and when to use field injections?

我有点懒惰,过去几乎完全使用现场注入。我只是提供空的构造函数,把我的@Inject 字段放在我的所有东西看起来都很好很简单。然而,字段注入有它的权衡,所以我设计了一些简单的规则来帮助我决定何时使用字段以及何时使用构造函数注入。如果我的逻辑有误或您有其他注意事项要补充,我将不胜感激。

为了达成一致,首先进行一些说明:

构造函数注入:

@Inject
public SomeClass(@Named("app version") String appVersion,
                    AppPrefs appPrefs) {...

与字段注入相同:

public class SomeClass {
    @Inject
    @Named("app version") String mAppVersion;

    @Inject
    AppPrefs appPrefs;

规则 1:如果我不控制对象 的创建,则必须使用字段注入(想想 Activity 或 Android 中的片段)。如果某些(非匕首感知)框架正在创建我的对象并将其处理给我,我别无选择,只能在收到实例后手动注入它。

规则 2:如果 class is/may 用于另一个不使用 Dagger 2 的项目,则必须使用构造函数注入。如果其他项目不使用 Dagger,则它们不能使用 DI,因此用户必须使用 new.

以 "old" 方式创建对象

规则 3:在使用 class 层次结构时优先使用构造函数注入,因为它更容易创建单元测试。

澄清:

考虑以下使用字段注入的结构:

package superclass;

public class SuperClass {
    @Inject
    HttpClient mHttpClient;
    ...
}

.

package differentpackage;

public class SubClass extends SuperClass {
    public SubClass() {
    }
}

当我在目录 test/java/differentpackage 中为 SubClass 创建单元测试时,我别无选择,只能启动整个 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 

所以基本上现在我处于另一个极端:我倾向于主要依赖构造函数注入并且仅在 'Rule 1' 适用时才使用字段注入。 我对构造函数注入的唯一 'problem' 是 'end' classes 构造函数有时会变得非常超载参数,它们看起来冗长且丑陋,如下所示:

@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
                    ) {

伙计们,在构造函数和字段注入之间进行选择的规则是什么?我遗漏了什么,我的逻辑有错误吗?

使用构造函数注入。如果不能,请使用 属性 注入。

规则 1 似乎没问题,像装饰或属性你可以使用 属性(字段) 注入。

规则 2 似乎没问题,因为谁使用你的 class 他们必须遵循你的构造函数。他们可能不知道他们还必须植入您的 属性。

规则 3 它不仅适用于单元测试。它适用于应用单一职责。更容易看到您的对象 graph.Otherwise 您将使用 属性.

隐藏它

如果我们提出您的问题,是的,您的构造函数中有很多参数。但是 解决方案不是 属性 注入 。您可以重构代码并使用 aggregate services