除了测试,为什么我们需要Dagger 2?

在这一点上,我对依赖注入(DI)的理解只是来自本文。我有兴趣尝试,但我只需要澄清一些事情:

  1. 许多人将 DI 称为减少样板代码的工具。但根据该教程,Dagger 2的设置往往会创建更多的配置类(模块和组件)。我没有尝试过,但从外观上看,它并没有减少代码,它只是将它们分开,所以主类看起来更整洁。我错了吗?
  2. 尽管Dagger 2声称DI不仅适用于测试,但许多人主要将其用于测试,包括Android自己的指南。您是否在生产就绪应用程序中使用过 Dagger 2?它对你有多大用处?
  3. 如果我对通过构造函数等创建传统的依赖关系感到非常舒服,我还需要看看Dagger 2吗?我觉得这个库可能有能力改变我编写RxJava的方式,我只是不确定它的好处是否像RxJava给我的那么多。

我知道,将Dagger与RxJava进行比较就像将苹果与橙色进行比较一样。但从某种意义上说,它们都是一种水果,就像Dagger和RxJava是第三方库一样,可能会使我的项目变得更大。


答案 1

你把两个独立的问题结合起来,应该分别评估:“为什么我们需要依赖注入?”和“为什么我们需要Dagger 2?”

依赖关系注入(控制反转)很有用,因为它允许组件的使用者提供组件的依赖关系。以日志格式化程序为例:如果没有依赖关系注入,您可能需要编写三个不同版本的类,这些版本将记录到 、远程服务器或文本文件。相比之下,如果你要写一个接受它写入的,那么你可以写一次,然后通过一个最合适的,包括一个测试替身(你制作的FakeWriter,或者一个StringWriter,或者一个模拟框架创建的mockWriter实例)进行测试。虽然它是为Guice而不是Dagger编写的,但我写了一个单独的SO答案,讨论了依赖注入在生产使用和测试用例中的价值;您看到的大多数教程都将重点放在测试上,前提是“生产”和“测试”是您预先了解的两种情况,其他重用和重新利用的机会将在以后出现。stdoutLogFormatterWriterWriter

一旦你接受了依赖注入为你提供的模块化、可重用性和可测试性优势,你可能会留下一个问题:我如何管理这些非常长的构造函数?毕竟,为了继续这个例子,如果不关心日志的去向,你将无法编写你的应用程序。LogFormatter

MyApplication application = new MyApplication(
    new LoggingService(new LogFormatter(new StdOutWriter())),
    new DatabaseService(new MyApplicationDatabase(new File("my.db"))),
    ...);

这就是Dagger闪耀的地方:它让你拥有依赖注入的所有好处,同时自动为你管理构造函数。这允许它封装创建对象的责任,并使其更干净,更安全,就像RxJava可以封装管理和传播异步事件的责任并使其更干净,更安全一样。

重要的是要意识到,Dagger 2在样板中的减少是与手动依赖注入相比,而不是与您正在比较的原始构造函数调用。如果你坚持直接调用,你可能会完全避免这种对象构造样板的大部分内容,但你也会发现自己正在经历困难的杂技,试图将工作分片给多个开发人员,或者试图测试或重用你编写的代码。集体的痛苦是为什么依赖注入这个概念如此受欢迎,以及为什么像Spring,Guice和Dagger这样的库越来越受欢迎。new

我可以保证在几个特别大,众所周知且使用良好的生产Android应用程序中使用Dagger 2。:)


答案 2

我只用过Dagger 1,但这可能仍然会以某种方式帮助你:

Dagger 构建了一个 (D)irected (a)cyclic (g)raph(这也是我这个名字的来源),其中包含用于不同目标应用程序的模块。

因此,在一个应用程序项目中,我们能够构建四个不同的应用程序,与Jake Wharton的u2020应用程序非常相似。所有这些应用程序都有不同的目标。一个是内部测试,一个是测试团队(带有截图功能),一个是内部发布,另一个是发布。

那么,为什么我们需要四个不同的应用程序呢?答案是:因此,我们不必在发布应用程序中使用调试或测试代码,并且可以将不属于一起的代码分开。

if(currentMode == Mode.DEBUG){
  Timber.i(...);
}

不再需要这样的东西。

前面提到的屏幕截图功能不属于生产代码,因此它只存在于测试代码中。在构建应用程序时,框架使用了正确的模块并注入了它。

注意:我相信匕首还有其他用例。

编辑:这不会像RxJava那样改变你编写代码的方式,但你必须在你的模块中经常使用DI。


推荐