【问题标题】:Why use Dagger or Hilt DI when I can use static functions?当我可以使用静态函数时,为什么还要使用 Dagger 或 Hilt DI?
【发布时间】:2020-10-24 22:48:43
【问题描述】:

我正在使用 Dagger2 和 Hilt 学习 DI,我有一个问题: 在创建 android 应用程序时,我注意到我使用了许多带有静态方法的实用程序类(即一个以摄氏温度接收温度并以华氏温度返回它的函数)。但是,我也使用一个带有静态实用程序方法的类(比如 NetworkUtils)来执行网络调用以从 API 获取数据(就像 Android Nanodegree 课程的讲师所做的那样): 我做的是这样的:

class NetworkUtils{
    public static String fetchCityName(double latitude, double longitude){
        // code for API call
    }
}

现在,当我从 Developer Docs 中学习 DI 原理时,我注意到网络调用是在实例方法内的实例类中进行的,并且它的参数是使用 Dagger 注入的。

  1. 为什么这与我所做的不同? 我读到静态方法使测试变得不容易,但是,假设我像文档显示的那样使用 DI,
  2. 为什么我必须实例化一个新的 NetworkUtils 对象,当我需要执行 API 调用时,而创建多个实例是无用的? 此外,官方文档说我们使用@Singleton 注解来设置函数范围(即对于 REST API 调用函数)应该是非常少见的,那么:
  3. 我是否应该为我需要使用的所有东西创建实例,即使它不需要? (昂贵的对象实例化除外)
  4. 最后,能否请您澄清一下实用程序类和我不应该在其中使用静态方法的普通类之间的区别?

谢谢。

【问题讨论】:

  • 这是一个非常广泛的问题,没有明确的答案。如果一个类是无状态的,那么注入它是没有意义的,因为所有实例都是平等的。 [我有理由期望像 NetworkUtils 这样的类有一些字段来指定要调用的后端等。考虑到您在此处显示的方法,它甚至可以是一个接口。]

标签: android dependency-injection dagger-2 dagger dagger-hilt


【解决方案1】:

现在,当我从 Developer Docs 中学习 DI 原则时,我 请注意,网络调用是在一个实例类中进行的 实例方法及其参数是使用 Dagger 注入的。

  1. 为什么这与我所做的不同?我读到静态方法使测试变得不容易,但是,假设我像使用 DI 文档显示,

我看到两个主要原因:

首先,当然是静态调用使代码难以测试。但是,是的,有一些测试框架可以为您完成工作并模拟静态调用。但是,无论何时使用它们 - 这很可能意味着您做错了什么或者您正在使用遗留代码。这就引出了第二个话题。

TDD - 测试驱动开发的理念是您首先编写测试,然后再编写代码。但测试“并不重要”。实际上,真正的结果是更好的代码!单元测试只是有帮助,但它们是子产品。大多数时候,好的代码和可测试的代码之间存在高度相关性。当你有静态调用和单例时,你可以很容易地从任何你想要的地方调用这个代码。结果是你停止思考设计,停止思考真正的 OOP 原则——什么是什么。您不会考虑额外的对象、对象之间的关系等。您最终会得到一个意大利面条代码。一切都与其他一切联系在一起。

  1. 为什么在创建多个实例时需要执行 API 调用时必须实例化 NetworkUtils 的新对象 没用?此外,官方文档说我们使用@Singleton 设置函数范围的注释(即用于 REST API 调用函数) 应该是非常罕见的,那么:

您说的是矛盾的 - “创建多个实例是无用的”。显然,创建实例而不使用静态调用可以帮助您获得更好且可测试的代码。也许您想知道它是否会影响性能。在这里我将引用.. 也许 Martin Fowler... 但在他关于重构的书中,他解释说 10 次中的 9 次优化都是无用的。你做得过火了。你需要编写好的代码。然后评价。那么如果需要优化——你有好的代码——优化会相对容易。

在你的情况下 - 不要担心。将网络调用包装在实例类中会导致多少个实例? 3? 5?当您评估收益时,这不是问题。

关于单例 - 您不需要共享状态 - 所以不需要单例。你会射中自己的脚。您将保留可以被垃圾收集的东西,为单例创建添加额外的代码等。只是简单的对象,仅此而已。

  1. 我是否应该为我需要使用的所有东西创建实例,即使它不需要? (昂贵的物品除外 实例化)

这是一个很大的问题。你应该读几本书,但仍然不知道答案。尝试使用 Uncle Bob 的 Clean Code 和 Martin Fowler 的 Refactoring。然后阅读一些认为自己做得过火的人的文章,并为自己找到平衡点。一般来说,你不应该使用“new”和任何静态调用。但是,例如,有很多关于 Android 上的单元测试真正有用的讨论,并且有很多人倾向于朝着这个方向前进您主要需要集成和端到端测试。我不会争论什么是正确的方法。

 4. Eventually, could you please clarify the difference between a utility class and a normal class that I should not use static methods
 in it?

基本上,您不应该使用“实用程序类”。他们的想法是包装一些代码,很多地方都用到了,但是没有涉及到状态。您不需要实例变量,因此静态方法是个好主意。但它会完全杀死你的测试。所以在你的情况下,你应该制作一种类型的类,如果你需要状态 - 添加,如果你不需要状态 - 就不要。然后你可以随意调用类。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2020-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多