java - Dagger 2 与注入(inject)器类

标签 java android unit-testing dependency-injection dagger-2

我刚开始使用 Dagger 2,想知道与我目前用来实现依赖注入(inject)的技术相比,它有什么优势。

目前,为了实现 DI,我创建了一个具有两种风格的项目:mock 和 prod。在这些风格中,我创建了一个名为 Injector 的类。

//prod Injector
public class Injector {
    public static INetworkLayer provideNetworkLayer() {
        return new ProductionNetworkLayer();
    }
}

//mock Injector
public class Injector {
    public static INetworkLayer provideNetworkLayer() {
        return new MockNetworkLayer();
    }
}

Injector 类对于我需要注入(inject)的每个对象都有一个静态方法。在我的应用程序代码中,我可以简单地编写:

INetworkLayer networkLayer = Injector.provideNetworkLayer();

这对于测试非常有用,因为在我的生产代码或测试代码中,我可以简单地告诉注入(inject)器我想要什么,并且根据我使用的构建变体,注入(inject)器将为我提供生产对象或模拟测试对象。如果我希望某个对象成为单例,我只需在 Injector 类中保存对它的引用,然后在调用 Provide...() 时给出该引用。

我已经开始在一个新项目中使用 Dagger2,并发现与我上面演示的“Injector”类方法相比,设置模拟/产品依赖项要困惑得多。

Dagger 2 的做法与“注入(inject)器类”方法有何不同?

有没有好的方法使用Dagger 2来提供mock和prod类?

最佳答案

am wondering what its advantages are over a technique that I currently use to achieve dependency injection.

自动依赖图解析,以及通过添加范围注释来限定范围的提供程序。

<小时/>

但是您的示例可以轻松转换为可与 Dagger2 一起使用的示例,请看:

//prod Injector
@Module
public class NetworkModule {
    @Provides
    @Singleton
    public static INetworkLayer provideNetworkLayer() {
        return new ProductionNetworkLayer();
    }
}

//mock Injector
@Module
public class NetworkModule {
    @Provides
    @Singleton
    public static INetworkLayer provideNetworkLayer() {
        return new MockNetworkLayer();
    }
}

还有

@Singleton
@Component(modules={NetworkModule.class})
public interface SingletonComponent {
    INetworkLayer provideNetworkLayer();
}

还有

public class Injector {
    private Injector() {
    }

    private static SingletonComponent singletonComponent;

    static {
        singletonComponent = DaggerSingletonComponent.create();
    }

    public static SingletonComponent get() {
        return singletonComponent;
    }
}

因为这样你就可以这样做:

INetworkLayer networkLayer = Injector.get().provideNetworkLayer();
<小时/> <小时/>

现在您可以问,“等一下,我已经这样做了,但现在需要更多代码来设置!”

那是因为您从未真正展示过如果您的依赖项相互依赖会发生什么。

例如,

@Module
public class NetworkModule {
    @Provides
    @Singleton
    public static INetworkLayer provideNetworkLayer(OkHttpClient okHttpClient) {
        return new ProductionNetworkLayer(okHttpClient);
    }

    @Provides
    @Singleton
    public OkHttpClient provideOkHttpClient() {
        return new /*create okHttpClient*/;
    }
}

而且,您实际上可以使用 @Inject 注解在一定程度上简化您的模块。尽管在使用接口(interface)时,它并不那么明显。

@Singleton
public class ProductionNetworkLayer {
    private OkHttpClient okHttpClient;

    @Inject
    public ProductionNetworkLayer(OkHttpClient okHttpClient) {
         this.okHttpClient = okHttpClient;
    }
}

@Module
public abstract class NetworkModule {
    @Binds
    public abstract INetworkLayer provideNetworkLayer(ProductionNetworkLayer productionNetworkLayer);
    // same as `public INetworkLayer prov(ProductionNetworkLayer prod) { return prod; }`

    @Provides
    @Singleton
    public OkHttpClient provideOkHttpClient() {
        return new /*create okHttpClient*/;
    }
}

关于java - Dagger 2 与注入(inject)器类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40752173/

相关文章:

带有搜索 View 的 Android 自定义 ActionBar

android - 在 Android 中创建通知应用程序?

java - 如何在 Spring MVC REST 测试中重定向模拟请求?

java - Ant SCP失败

java - 使用 java 替换文件中包含的文件名并用新名称重命名文件

java - Java 程序如何跟踪其运行期间使用的最大实际堆大小?

scala - Spark scala mocking spark.implicits 用于单元测试

java - Java 7 上 JCombobox 的类型安全

android - EditTextPreference 导致膨胀异常

typescript - Angular 测试,为不同的测试用例动态更改 ActivatedRoute 参数