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

标签 java dependency-injection dagger-2

我有点懒惰,过去几乎完全使用现场注入(inject)。我只是提供了空的构造函数,把我的@Inject 字段放在我的一切看起来很漂亮和简单。然而,字段注入(inject)有其权衡,因此我设计了一些简单的规则来帮助我决定何时使用字段以及何时使用构造函数注入(inject)。如果我的逻辑有错误或您有其他考虑要添加,我将不胜感激。

首先要澄清一下,以便在同一页面上:

构造函数注入(inject):

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

与字段注入(inject)相同:

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

    @Inject
    AppPrefs appPrefs;

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

规则 2:如果该类被/可能在另一个不使用 Dagger 2 的项目中使用,则必须使用构造函数注入(inject)。如果其他项目不使用 Dagger,他们就不能使用 DI,因此用户必须使用 new 以“旧”方式创建对象。

规则 3:使用类层次结构时首选构造函数注入(inject),因为它更容易创建单元测试。

澄清:

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

package superclass;

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

.

package differentpackage;

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

当我在 test/java/differentpackage 目录中为 SubClass 创建单元测试时,我别无选择,只能启动整个 DI 基础架构以便能够注入(inject) HttpClient。相反,如果我像这样使用构造函数注入(inject):

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 

所以基本上现在我处于另一个极端:我倾向于主要依赖构造函数注入(inject),并且仅在“规则 1”适用时才使用字段注入(inject)。 我对构造函数注入(inject)的唯一“问题”是,对于“结束”类,构造函数有时会因参数而变得非常重载,它们看起来像这样冗长而丑陋:

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

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

最佳答案

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

规则 1 似乎没问题,比如可以使用 Property(field) 注入(inject)的装饰或属性。

规则 2 似乎没问题,因为谁使用你的类,他们必须遵循你的构造函数。他们可能不知道他们还必须对您的属性(property)进行改造。

规则 3 这不仅适用于单元测试。这对应用单一职责很有好处。更容易看到您的对象图。否则您将使用属性隐藏它。

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

关于java - Dagger 2 : When to use constructor injections and when to use field injections?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36078137/

相关文章:

Java:通用类异常

java - 扩展抽象类后的方法

asp.net-mvc-4 - 可以使用 CaSTLe Windsor 在 ASP.NET MVC 4 中实现 IDependencyResolver 吗?

java - 根据类的类型将 Map<String,Object> 注入(inject)到构造函数中

java - 将 jasper 报告导出为 XLS 格式时,未发生单元格扩展

java - 动态规划 - 子集和 - 重建路径

java - 设计模式 - 如何仅在某些情况下强制执行对象属性(构建器模式、依赖注入(inject))

java - Dagger 2 : Using factory methods in place of public constructors

android - 如何使用 Dagger2 将 Activity 范围内的依赖项替换为模拟

android - 错误 [Dagger/MissingBinding] androidx.lifecycle.ViewModelProvider.Factory cannot be provided without an @Provides-annotated method