匕首2:何时使用构造注射以及何时使用注射?

Ogn*_*yan 22 java dependency-injection dagger-2

我有点懒惰,习惯几乎完全用场注射.我只是提供空构造函数,把我的@Inject字段我看起来很好很简单.然而,现场注入有其权衡,所以我设计了一些简单的规则,帮助我决定何时使用字段以及何时使用构造函数注入.如果我的逻辑中存在错误或者您需要添加其他注意事项,我将不胜感激.

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

构造函数注入:

@Inject
public SomeClass(@Named("app version") String appVersion,
                    AppPrefs appPrefs) {...
Run Code Online (Sandbox Code Playgroud)

与现场注入相同:

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

    @Inject
    AppPrefs appPrefs;
Run Code Online (Sandbox Code Playgroud)

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

规则2:如果该类是/可能在另一个不使用Dagger 2的项目中使用,则必须使用构造函数注入.如果其他项目不使用Dagger,则他们不能使用DI,因此用户必须使用"旧"方式创建对象new.

规则3:使用类层次结构时PREFER构造函数注入,因为它更容易创建单元测试.

澄清:

考虑以下使用现场注入的结构:

package superclass;

public class SuperClass {
    @Inject
    HttpClient mHttpClient;
    ...
}
Run Code Online (Sandbox Code Playgroud)

.

package differentpackage;

public class SubClass extends SuperClass {
    public SubClass() {
    }
}
Run Code Online (Sandbox Code Playgroud)

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

public class SuperClass {
    private final HttpClient mHttpClient;

    @Inject
    public SuperClass(HttpClient httpClient) {
        mHttpClient = httpClient;
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的单元测试中我可以简单地说:

HttpClient mockHttp = mock(HttpClient.class);

Subclass tested = new Subclass(mockHttp);

// tests 
Run Code Online (Sandbox Code Playgroud)

所以基本上现在我处于另一个极端:我倾向于主要依赖构造函数注射并仅在"规则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
                    ) {
Run Code Online (Sandbox Code Playgroud)

伙计们,你在构造函数和字段注入之间做出选择的规则是什么?我错过了什么,我的逻辑中有错误吗?

Erk*_*rel 7

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

规则1似乎没问题,就像装饰或属性一样,你可以使用Property(field)注入.

规则2似乎没问题,因为谁使用你的类他们必须遵循你的构造函数.他们可能不知道他们也必须为你的财产提供服务.

规则3这不仅对单元测试有益.应用Single Responsibilty是有好处的.您可以更轻松地查看对象图.否则,您将使用属性隐藏它.

如果我们提出你的问题,是的,你的构造函数中有很多参数.但解决方案不是财产注入.您可以重构代码并使用聚合服务