在 Android 中使用(出)DI 容器(Dagger 1)进行适当的依赖注入
Proper dependency injection in Android with(out) DI containers (Dagger 1)
我目前正在开发(实际上是构建)一个 Android 应用程序,该应用程序具有蓝牙连接和与 RESTful 服务的 HTTP 通信。我碰巧遇到了一个名为 Dagger 的 "dependency injection" 框架,它对我来说是非常具有革命性的。然而,我开始更多地考虑依赖注入的 "true spirit" 并遇到更多博客 posts/opinions 解释这个概念并实际建议使用 "constructor injection" 并标记其他(字段和 setter 次注射)作为 "anti-patterns."
我确实得到了他们对通过 DI 框架的字段和 setter 注入的关注,因为前者没有明确揭示对象的依赖关系,而后者没有严格依赖 "required." 但是有些声音强烈认为唯一有效且有用且真正面向对象的依赖注入方式是构造函数注入。
我特别担心 Android。开发一个 Android 应用程序意味着要处理很多活动、服务、片段、广播接收器等,其中许多不让我们处理构造函数。要使用 DI 容器 (Dagger) 提供依赖项,我只需要对依赖项使用字段注入。 为什么不使用 POJO 工厂? 使用 DI 框架进行字段注入的唯一优势似乎是能够提供单独的模块(一个用于生产,一个注入模拟对象用于测试),但是我不知道是否值得引入性能开销(如果有的话)。
就目前而言,在我严格限制的观点中,使用 Dagger 的唯一优势是减少编写的代码量并避免连接对象以正确传递依赖项带来的麻烦。
因此,我得出一个结论,我可能完全误解了依赖注入的概念or/and我错过了使用 Dagger 的正确方法,or/and 也许我在面向对象的设计中过于固执己见(或者只是不够称职)。
请教我正确使用 DI 容器和缺少 insight/understanding!
TL;DR: 不必一起处理接线 类 是一个巨大的优势,在重构期间不必重新接线是一个更大的优势.
我发现你的 "only advantage" 仍然是一个巨大的优势。恕我直言,当您添加或重构现有代码时,DI 最有价值的部分就出现了。我经常遇到这样一种情况,即依赖图的 "leaf" 处的某些东西需要来自图根的一些额外的东西(即 UserStorageHelper 需要一个上下文)。如果没有 DI,则有必要通过某些根和目标依赖项之间的构造函数 and/or onCreate/onAttach 的每一层传递该对象。 DI 将允许您以最小的重构成本添加该依赖项。 IMO,它使代码更易于理解,因为在每个级别,您都可以检查并说 "this object needs some set of dependencies"。这些对象具有的任何子依赖性都不是立即有用的信息,但您也可以轻松检查。 (如果你想要一个概览,Dagger 也会生成依赖图,我认为这非常简洁。)
与此相反,更改 "leaf" 对象的依赖项可能会导致图表产生涟漪效应,但不一定立即显而易见。但是,当您需要修改依赖关系图中的每个构造函数时,我通常发现修复 DI 问题比潜在的大规模重构更好。
关于改用 POJO 工厂的建议,在我看来你仍然有同样的依赖问题。工厂的每一层都需要另一个工厂来获取其依赖项。自己编写似乎同样乏味,因此您可以通过代码生成它,但现在您基本上只有 dagger 的 Provider。
除了在测试中提供不同的实现之外,我还广泛使用它来处理构建 flavours/dimensions/build 类型(注入不同类型的记录器模块?无操作与真正的广告模块?)。
最终,有用性完全取决于您的项目。 Dagger/DI 在很多情况下都非常有用,但不是在所有情况下。有点像多功能工具,您可以通过多种不同的方式使用它。有时这是矫枉过正(您只需要一把螺丝刀,而不是酒瓶开瓶器),有时它根本无法解决您的问题(无论您多么努力,它都无法成为一把好锤子)。唯一需要注意的是,在以后添加 DI 比从一开始就使用它要困难得多,所以我倾向于在项目开始时将它作为矫枉过正的选项添加,而不是进入一个项目并希望我已经拥有它。
我目前正在开发(实际上是构建)一个 Android 应用程序,该应用程序具有蓝牙连接和与 RESTful 服务的 HTTP 通信。我碰巧遇到了一个名为 Dagger 的 "dependency injection" 框架,它对我来说是非常具有革命性的。然而,我开始更多地考虑依赖注入的 "true spirit" 并遇到更多博客 posts/opinions 解释这个概念并实际建议使用 "constructor injection" 并标记其他(字段和 setter 次注射)作为 "anti-patterns."
我确实得到了他们对通过 DI 框架的字段和 setter 注入的关注,因为前者没有明确揭示对象的依赖关系,而后者没有严格依赖 "required." 但是有些声音强烈认为唯一有效且有用且真正面向对象的依赖注入方式是构造函数注入。
我特别担心 Android。开发一个 Android 应用程序意味着要处理很多活动、服务、片段、广播接收器等,其中许多不让我们处理构造函数。要使用 DI 容器 (Dagger) 提供依赖项,我只需要对依赖项使用字段注入。 为什么不使用 POJO 工厂? 使用 DI 框架进行字段注入的唯一优势似乎是能够提供单独的模块(一个用于生产,一个注入模拟对象用于测试),但是我不知道是否值得引入性能开销(如果有的话)。
就目前而言,在我严格限制的观点中,使用 Dagger 的唯一优势是减少编写的代码量并避免连接对象以正确传递依赖项带来的麻烦。
因此,我得出一个结论,我可能完全误解了依赖注入的概念or/and我错过了使用 Dagger 的正确方法,or/and 也许我在面向对象的设计中过于固执己见(或者只是不够称职)。
请教我正确使用 DI 容器和缺少 insight/understanding!
TL;DR: 不必一起处理接线 类 是一个巨大的优势,在重构期间不必重新接线是一个更大的优势.
我发现你的 "only advantage" 仍然是一个巨大的优势。恕我直言,当您添加或重构现有代码时,DI 最有价值的部分就出现了。我经常遇到这样一种情况,即依赖图的 "leaf" 处的某些东西需要来自图根的一些额外的东西(即 UserStorageHelper 需要一个上下文)。如果没有 DI,则有必要通过某些根和目标依赖项之间的构造函数 and/or onCreate/onAttach 的每一层传递该对象。 DI 将允许您以最小的重构成本添加该依赖项。 IMO,它使代码更易于理解,因为在每个级别,您都可以检查并说 "this object needs some set of dependencies"。这些对象具有的任何子依赖性都不是立即有用的信息,但您也可以轻松检查。 (如果你想要一个概览,Dagger 也会生成依赖图,我认为这非常简洁。)
与此相反,更改 "leaf" 对象的依赖项可能会导致图表产生涟漪效应,但不一定立即显而易见。但是,当您需要修改依赖关系图中的每个构造函数时,我通常发现修复 DI 问题比潜在的大规模重构更好。
关于改用 POJO 工厂的建议,在我看来你仍然有同样的依赖问题。工厂的每一层都需要另一个工厂来获取其依赖项。自己编写似乎同样乏味,因此您可以通过代码生成它,但现在您基本上只有 dagger 的 Provider。
除了在测试中提供不同的实现之外,我还广泛使用它来处理构建 flavours/dimensions/build 类型(注入不同类型的记录器模块?无操作与真正的广告模块?)。
最终,有用性完全取决于您的项目。 Dagger/DI 在很多情况下都非常有用,但不是在所有情况下。有点像多功能工具,您可以通过多种不同的方式使用它。有时这是矫枉过正(您只需要一把螺丝刀,而不是酒瓶开瓶器),有时它根本无法解决您的问题(无论您多么努力,它都无法成为一把好锤子)。唯一需要注意的是,在以后添加 DI 比从一开始就使用它要困难得多,所以我倾向于在项目开始时将它作为矫枉过正的选项添加,而不是进入一个项目并希望我已经拥有它。