在构造函数上使用Dagger和@Inject-是还是不是?

2023-11-23 06:40

本文主要是介绍在构造函数上使用Dagger和@Inject-是还是不是?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Depending who you speak to, putting @Inject on a constructor is either akin to whipping your own grandmother or is such a blindingly obvious thing to do that the question is ridiculous.

根据与您交谈的人的不同,将@Inject放在构造函数上要么类似于鞭打自己的祖母,要么是一件令人眼花obvious乱的事情,以至于这个问题很荒谬。

But which is right?

但是哪个是对的?

波比人 (The Bobites)

These folk have been fully converted to the teachings of Uncle Bob — the father of clean code and clean architecture. Abstraction is our redemption and those who choose to ignore abstraction will burn in the fiery pits of hell.

这些人已经完全转换为Bob叔叔的教义-干净的代码和干净的建筑之父。 抽象是我们的救赎,那些选择忽略抽象的人将在火热的地狱中燃烧。

Or, more simply, Dagger is an implementation detail — a third party library. Our codebase should be able to function regardless of how DI is implemented. Say a library is scattered throughout your code base — this is bad.

或者,更简单地说,Dagger是实现细节-第三方库。 无论如何实现DI,我们的代码库都应该能够运行。 假设库分散在您的整个代码库中,这很不好。

Codebases live for a long time, and at some point that library is going to have breaking changes, or become unsupported, or a new shiny library will come out. In an ideal world, changing the library means only a few small changes to a small part of your codebase.

代码库的生存时间很长,有时库将发生重大更改,或者变得不受支持,否则将出现新的闪亮库。 在理想的世界中,更改库意味着仅对代码库的一小部分进行少量更改。

If Dagger implementation details (i.e. @Inject) are scattered throughout your codebase, your codebase becomes resistant to change, not to mention the rest of the codebase has added complexity.

如果Dagger实现细节(即@Inject)散布在您的整个代码库中,则您的代码库将变得难以更改,更不用说其余的代码库增加了复杂性。

Belief: Never use Dagger goodies like @Inject on constructors!

信念:切勿在构造函数上使用@Inject之类的Dagger东西!

Principle to live by: Abstraction is king

生存原则:抽象为王

飞船 (The Shipits)

These folk have seen examples of all those clean architecture code bases and honestly they look more trouble than they’re worth. We’re only trying to build an app, not architect the Golden Gate Bridge.

这些人看到了所有这些干净的体系结构代码库的示例,说实话,它们看起来比他们值得的麻烦更多。 我们仅尝试构建一个应用程序,而不是架构师金门大桥。

Dagger has this fancy annotation processing and code generation functionality that makes our lives easier, why on earth would we not use it?

Dagger具有这种精美的注释处理和代码生成功能,使我们的生活更轻松,为什么我们不使用它呢?

Why would we write a DI definition for every single class in an object graph — duplicating the objects constructor — so any changes to the constructor need made in several places? After all, Dagger will do the heavy lifting for us with one itsy bitsy @Inject annotation.

为什么我们要为对象图中的每个单个类编写一个DI定义(复制对象构造函数),以便需要在多个地方对构造函数进行任何更改? 毕竟,Dagger将为我们提供繁重的@Inject注释。

And let’s be honest, DI frameworks only change once every 2–4 years, what’s the point of abstracting something that more than likely won’t change for the entire time we’ll be working on the project?

老实说,DI框架每2-4年仅更改一次,那么抽象一个在我们进行项目的整个过程中很可能不会更改的东西有什么意义呢?

Belief: Always use @Inject on constructors!

信念:始终在构造函数上使用@Inject!

Principle to live by: Don’t Repeat Yourself (DRY)

赖以生存的原则:不要重复自己(DRY)

When you come down to it, abstraction and DRY code are two fundamental principles of programming — each equally correct. But, in this case, to use one is to break the other. This in itself is nothing new, there’s so many principles of programming that almost any choice you make is bound to break one principle or another.

当您深入到它时,抽象和DRY代码是编程的两个基本原理-每个都正确。 但是,在这种情况下,使用其中一种会破坏另一种。 这本身并不是什么新鲜事物,编程的原理如此之多,以至于您做出的几乎任何选择都必然会破坏一种或另一种原理。

But if that’s the case, how to choose which principle is more important, so which one you should adhere to? In order to make that choice, you need to evaluate each approach by something.

但是,如果是这样,那么如何选择更重要的原则,那么您应该坚持哪个原则呢? 为了做出选择,您需要通过某种方式评估每种方法。

Many principles of programming have a basis in saving development time. Whether that's sacrificing time now to spend longer implementing a feature which is then incredibly quick to change in the future. Or choosing the quick implementation route now knowing that you’ll pay the debt (and then some) of that saved time on maintenance in the future.

编程的许多原理都有节省开发时间的基础。 现在是否要花费时间来花费更长的时间来实现一项功能,而该功能在未来会Swift地改变。 或者现在就选择快速实施路线,因为您知道自己将来会偿还(节省了)节省下来的维护时间上的债务(然后还清了一部分)。

It’s often easier to worry about the present and choose the quick implementation route, even when the time debt you incur is much bigger than the time saved.

即使当您承担的时间债务比节省的时间大得多时,通常也更容易担心现在的情况并选择快速的实施途径。

Principles we follow — quasi religiously — are to trick our present selves into making better choices which help us write code that takes less time for our future selves, or some other poor developer that takes over our codebase to maintain or change in the future.

我们遵循的原则(半信半疑地)是欺骗我们目前的自我做出更好的选择,以帮助我们编写使自己将来花费更少时间的代码,或者其他一些贫穷的开发人员接管我们的代码库,以维护或更改未来。

So perhaps we can evaluate which principle to choose based on time — the amount of time it takes to implement, maintain, and change.

因此,也许我们可以根据时间评估选择哪种原则,即实施,维护和更改所花费的时间。

Let’s see how both methods stack up.

让我们看看这两种方法是如何叠加的。

@无处不在 (@Inject everywhere)

In this hypothetical codebase @Inject is used all over. You can’t look at an object constructor without seeing that pesky annotation. For the developers that wrote it, you can count the seconds to implement with one hand.

在此假设的代码库中,全部使用@Inject。 您必须先查看该讨厌的注解,才能查看对象构造函数。 对于编写它的开发人员,您可以用一只手计算实现的秒数。

Image for post

Maintenance is also pretty simple. Any time an object in the constructor was changed, Dagger re-generated the object graph definition automatically.

维护也很简单。 每当更改构造函数中的对象时,Dagger都会自动重新生成对象图定义。

Image for post

But, one day, a bright spark decided Dagger bad, Koin good. So the team embark on the unenviable task of ridding the codebase of Dagger and adding Koin — coincidently the same team will at some point in the near future be planning on how to migrate to Hilt.

但是,有一天,明亮的火花决定了匕首不好,科恩很好。 因此,团队开始了一项艰巨的任务:删除Dagger的代码库并添加Koin-巧合的是,同一团队将在不久的将来计划如何迁移到Hilt。

Let’s see how they got on.

让我们看看他们如何相处。

Image for post
A quick find and replace (CMD+SHIFT+R)
快速查找并替换(CMD + SHIFT + R)

And don’t forget, sometimes this part wouldn’t even be needed. After all @Inject is part of Java (JSR330) and is used by other JVM dependency injection libraries like Guice and Toothpick.

并且不要忘记,有时甚至不需要这部分。 毕竟@Inject是Java( JSR330 )的一部分,并由Guice和Toothpick等其他JVM依赖项注入库使用。

All in all this method has been pretty quick. Minimal lines of code needed written in the first place for DI to function, maintenance was a breeze, and removing Dagger from the codebase was super quick (if it even needs removed in the first place).

总而言之,这种方法很快。 首先,要使DI起作用,需要编写最少的代码行,维护起来很容易,并且从代码库中删除Dagger非常快捷(如果甚至需要首先删除它)。

How does abstraction compare?

抽象如何比较?

抽象DI (Abstracted DI)

In this codebase DI has been thoroughly abstracted. DI is fully inside a single package and none of the rest of the codebase has any idea DI exists, let alone what library is used to implement it. So an injection looks something like this:

在此代码库中,对DI进行了彻底的抽象。 DI完全放在一个包中,而代码库的其余部分都不知道DI存在,更不用说使用什么库来实现它了。 因此,注入看起来像这样:

Image for post

These are more lines of code as we’re not using Daggers code generation so it has taken longer to write, but we’re sure to save that time in the future.

这些是更多的代码行,因为我们没有使用Daggers代码生成,因此花费了更长的时间编写,但是我们肯定会在将来节省时间。

Now during maintenance when a constructor argument needs added or removed.

现在在维护期间,需要添加或删除构造函数参数。

Image for post

Not ideal, every change really requires three changes, and let’s not forget the problem with non-DRY code.

这并不理想,每个更改实际上都需要进行三个更改,我们不要忘记非DRY代码的问题。

Image for post
Compile time failure when forgetting to make a change in one of the 3 places.
忘记在3个地方之一进行更改时,编译时失败。

So maintenance takes significantly longer. But the benefit really comes when switching DI libraries, not a single change needs made in the rest of your codebase. A genuine, if costly (in this case), benefit.

因此,维护需要更长的时间。 但是,真正的好处是切换DI库时,而不是在其余代码库中进行的单个更改。 真正的(如果是昂贵的话)收益(在这种情况下)。

In this slightly contrived example using @Inject is quite clearly quicker. Even in this short example ~1 minute is saved all round by using Dagger’s inbuilt code generation.

在这个稍作设计的示例中,使用@Inject显然更快。 即使在这个简短的示例中,使用Dagger的内置代码生成也可以节省大约1分钟的时间。

This may sound small, but imagine a codebase with multiple developers working for several years, the combined time saving can add up to days of development time. Not to mention the reduction in boilerplate code, after-all, who enjoys writing boilerplate?

这听起来似乎很小,但是可以想象一个有多个开发人员一起工作了几年的代码库,节省下来的时间总共可以增加几天的开发时间。 更何况样板代码的减少,毕竟,谁喜欢编写样板?

But there are drawbacks to using @Inject on constructors and less easily definable benefits to abstraction. For instance:

但是在构造函数上使用@Inject有缺点,而抽象的好处则较难定义。 例如:

  • Classes don’t know about DI and DI info is limited to one layer, limiting the complexity overhead of the codebase.

    类不了解DI,并且DI信息仅限于一层,从而限制了代码库的复杂性开销。
  • Visualising the DI graph is easier with DI code in one package — new tools like Scabbard and the Dagger Visualiser in Android Studio 4.2 make this less important.

    使用一个程序包中的DI代码,可视化DI图形更加容易-像Android Studio 4.2中的Scabbard和Dagger Visualiser这样的新工具使这一点变得不那么重要了。
  • Implementations are hidden from the object graph so they can’t be accidentally injected.

    实现从对象图中隐藏起来,因此不会被意外注入。
  • Finding and replacing @Inject across an entire codebase will cause merge headaches if there are multiple active branches when it’s done.

    如果完成时有多个活动分支,则在整个代码库中查找和替换@Inject将导致合并麻烦。

These are very valid concerns. But, do you think these concerns save more time than having DRY code and letting Dagger do the heavy lifting for you?

这些是非常有效的担忧。 但是,您是否认为这些问题比拥有DRY代码并让Dagger为您省力的事情节省了更多时间?

The answer for most codebases is probably no.

大多数代码库的答案可能是“否”。

结论 (Conclusion)

Every choice made while coding is a trade-off. Maybe in your situation it makes complete sense to fully abstract your DI. But before you make that decision, ask yourself, are you making that decision because someone told you to, or are you making that decision because it makes your specific codebase easier (and quicker) to implement, maintain, and change for you and future developers?

编码时做出的每个选择都是一个权衡。 也许在您的情况下,完全抽象您的DI完全有意义。 但是在做出决定之前,请先问自己,是因为有人告诉您做出决定,还是要做出决定,是因为这样做会使您和将来的开发人员更容易(更快)实施,维护和更改特定的代码库?

奖金 (Bonus)

Even when using @Inject regularly, one common use of manually calling constructors in Dagger modules is for when injecting interfaces rather than implementations. Dagger has a way of dealing with this without duplicating object constructors, @Binds to the rescue.

即使定期使用@Inject,在Dagger模块中手动调用构造函数的一种常见用法是在注入接口而非实现时使用。 Dagger有一种无需复制对象构造函数即可解决的方法,@Binds可以帮助您。

class ThisClassDoesFunStuffImpl @Inject constructor(private val someUseCase: SomeUseCase
) : ThisClassDoesFunStuff@Module
interface BindInterfacesModule {@Bindsfun myInterface(thisClassDoesFunStuffImpl: ThisClassDoesFunStuffImpl): ThisClassDoesFunStuff}

Vehemently disagree? Stick in a comment!

强烈不同意? 留下评论!

翻译自: https://proandroiddev.com/dagger-and-inject-on-constructors-do-or-dont-9d97e7c93f84


http://www.taodudu.cc/news/show-8355575.html

相关文章:

  • java无法访问某个源文件_java中jar包内的类访问jar包内部的资源文件的路径问题详解...
  • java界面输出档案_从 Java 档案 (JAR) 中读取文件
  • java 读 jar外文件_Java 获取 jar包以外的资源操作
  • ppt_powerbi转ppt,数据分析ppt
  • Linux性能调试工具之ftrace
  • Hive分区表增删字段(解决alter table失败问题)
  • 鼠标/光标变为旋转的圆圈
  • 虚幻4渲染编程(光线追踪篇)【第四卷:Realtime Raytracing In UE4】
  • McBsp接口使用和概念
  • [DevExpress]ASP.NET控件ASPxComboBox组合框小结(一)
  • 从模拟MMU设计一个路由表的失败到DxR的回归
  • 关于下载、编译及运行DirectX Raytracing Sample Code (DXR)若干小问题及解决方法
  • DxR路由查找算法前传
  • Raman拉曼测试(型号Thermo Fisher DXR 2xi)
  • 【DXR/UE4】DXR教程/UE4RTAO
  • dxr学习笔记
  • DXR相关
  • DXR
  • 我所理解的DirectX Ray Tracing
  • 华卫恒源获数百万元天使轮融资,清华水木创投投资
  • 清华游记
  • Ubuntu镜像下载(清华镜像)
  • 水木清华论坛怎么进_秒秒秒!2年经验进腾讯上班是一种什么神仙体验,带上我的Java社招面经分享...
  • 清华为什么被称为“水木清华”
  • 听歌时收集的段子
  • 再听《不是因为寂寞才想你》,发现已经是十年前的老歌了
  • ffmpeg 下载国际在线的intervideo,的不老歌
  • 就是喜欢听西北风情的歌
  • 听一首老歌都会流泪的女孩我要怎么爱.
  • 再听老歌
  • 这篇关于在构造函数上使用Dagger和@Inject-是还是不是?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



    http://www.chinasem.cn/article/416082

    相关文章

    Pydantic中Optional 和Union类型的使用

    《Pydantic中Optional和Union类型的使用》本文主要介绍了Pydantic中Optional和Union类型的使用,这两者在处理可选字段和多类型字段时尤为重要,文中通过示例代码介绍的... 目录简介Optional 类型Union 类型Optional 和 Union 的组合总结简介Pyd

    Vue3使用router,params传参为空问题

    《Vue3使用router,params传参为空问题》:本文主要介绍Vue3使用router,params传参为空问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录vue3使用China编程router,params传参为空1.使用query方式传参2.使用 Histo

    使用Python自建轻量级的HTTP调试工具

    《使用Python自建轻量级的HTTP调试工具》这篇文章主要为大家详细介绍了如何使用Python自建一个轻量级的HTTP调试工具,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录一、为什么需要自建工具二、核心功能设计三、技术选型四、分步实现五、进阶优化技巧六、使用示例七、性能对比八、扩展方向建

    使用Python实现一键隐藏屏幕并锁定输入

    《使用Python实现一键隐藏屏幕并锁定输入》本文主要介绍了使用Python编写一个一键隐藏屏幕并锁定输入的黑科技程序,能够在指定热键触发后立即遮挡屏幕,并禁止一切键盘鼠标输入,这样就再也不用担心自己... 目录1. 概述2. 功能亮点3.代码实现4.使用方法5. 展示效果6. 代码优化与拓展7. 总结1.

    使用Python开发一个简单的本地图片服务器

    《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

    Linux中的计划任务(crontab)使用方式

    《Linux中的计划任务(crontab)使用方式》:本文主要介绍Linux中的计划任务(crontab)使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言1、linux的起源与发展2、什么是计划任务(crontab)二、crontab基础1、cro

    kotlin中const 和val的区别及使用场景分析

    《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

    C++变换迭代器使用方法小结

    《C++变换迭代器使用方法小结》本文主要介绍了C++变换迭代器使用方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、源码2、代码解析代码解析:transform_iterator1. transform_iterat

    C++中std::distance使用方法示例

    《C++中std::distance使用方法示例》std::distance是C++标准库中的一个函数,用于计算两个迭代器之间的距离,本文主要介绍了C++中std::distance使用方法示例,具... 目录语法使用方式解释示例输出:其他说明:总结std::distance&n编程bsp;是 C++ 标准

    vue使用docxtemplater导出word

    《vue使用docxtemplater导出word》docxtemplater是一种邮件合并工具,以编程方式使用并处理条件、循环,并且可以扩展以插入任何内容,下面我们来看看如何使用docxtempl... 目录docxtemplatervue使用docxtemplater导出word安装常用语法 封装导出方