写点什么

依赖注入是否值得?

  • 2007-12-14
  • 本文字数:1552 字

    阅读完需:约 5 分钟

在博客的世界里进行了一场关于使用依赖注入(DI)之优点和缺点的有趣讨论。论题是:依赖注入是否真的值得?

讨论始自 Jacob Proffitt ,他撰文解释他的观点说,依赖注入的伸缩性不好。据 Proffitt 认为,DI 流行的唯一原因是 Mocking。

DI 进来这么流行的真实原因,和正交性、封装性或者其他“纯粹的”架构考量都没有关系。真正的原因是很多开发者都用 DI 来帮助使用 Mock 对象进行单元测试。随你怎么说,这个因素实际上说服了聪明的开发者选择 DI 而不是更简单的实现。

Proffitt 甚至声称 DI 只对单元测试有好处:

不管怎样,我真的希望人们能够承认 DI 除了单元测试之外,没什么其他有说服力的应用。

不过,Proffitt 虽然做单元测试,却不用 DI。他使用 TypeMock 框架。这个框架可以拦截对依赖对象的调用,哪怕依赖是在被测试代码中创建的。这意味着 Proffitt 不用解耦他的对象也能为单元测试创建 Mock。

Ayende RhinoMocks 的创造者,他在自己的博客上回应说

虽然能够方便地编写 Mock 代码是很棒的特性,但这只是主要利益之外的附带好处,主要的利益是降低了对象间的耦合。我可以修改数据访问部分的代码,而不需要触及负责工资计算的引擎,这是我得到的主要益处。

Nate Kohari 也回答了 Proffitt 的原帖。Kohari 不但给出了一个 DI 的代码示例,还详细阐述了什么是真正的 DI

如果你是 GoF 的爱好者,这其实就是 Strategy 模式。依赖注入(按照我的观点)本质上是大规模使用的 Strategy 模式。

Kohari 是 NInject DI 框架的作者,他强烈反对 DI 框架无用的说法:

一旦你开始倚靠 DI 框架来编写代码,连接对象所需的代价就下降到接近于零。于是,要想达到单一职责的目标,其难度会指数级地下降。

在随后的帖子中,Kohari 重申了使用框架的重要性,以此来回应Proffitt 原先认为 DI 的伸缩性不佳的说法:

在真实世界的使用场景中,手工进行的依赖注入的确伸缩性不佳。

Proffitt 不同意:

你怎么能说依赖注入(我不是针对整个控制反转模式,但也未尝不可。只是还没轮到。)创造了易于复用的松散耦合的单元?DI 本身就要求调用者去提供被调用者的所需。任何理性的评价都会认为这是提高了耦合程度。把耦合的负担丢给框架并不能改变事实,使用一个对象,仍然需要先给它提供外部的东西。

Kohari 解释在大多数情况下,如何创建和注射特定类型的对象只需要配置一次,而且是由框架完成的,不是由调用者。

Kohari 还谈到了代码的变化能力:

……简单来说,依赖注入让你的代码更容易改变。这就是它在敏捷社群中流行的原因,他们的整个软件开发实践都围绕着快速变化。

Eli Lopian 是设计出 TypeMock 的公司的 CTO 也加入争论,他对争论的核心有不同的看法:

当你把 DI 当作是“银弹”来使用,你就丧失了所用编程语言的一大半能力。你不能用静态方法,不能用“new”关键字,不能用封闭类型。哦,你还要把所有的方法都变成虚拟的。

他还争辩说,仅仅为了方便变化而使用 DI,违背了 YAGNI 原则

Lopian 继续说:

TDD 刚兴起时,首先被讨论的一个问题就是“我们是否应该修改代码来满足可测试的要求?”我们应不应该改变代码的可见性?我们应不应该改变代码的设计?这个问题导致了可测试的代码与 OO 封装性之间的冲突。开发者们开始为了能够测试,而把代码中的私有部分暴露出来。开头只是私有方法和属性,现在扩大到了整个设计。

这是一个老问题了。有些人认为改变代码让它更容易测试是一件好事;其他人认为这样做打破了封装性,因此是坏事。

Kohari 对封装与依赖的的关系提出了看法:

这是让依赖注入物有所值的秘密:当谈到依赖的时候,封装是坏的。

如果出于单元测试的意图而改变代码,能让耦合变得更松散(Proffitt 对此有所质疑)——这是不是一件好事呢?

松散耦合与封装都是重要的 OO 特征,那我们如何作出平衡呢?哪条路才是对的?

查看英文原文: Does Dependency Injection pay off?

2007-12-14 04:204620
用户头像

发布了 225 篇内容, 共 69.6 次阅读, 收获喜欢 52 次。

关注

评论

发布
暂无评论
发现更多内容

Android NDK开发,使用ndk-build编译,androidkotlin教程

android 程序员 移动开发

Android ShapeableImageView使用详解,告别shape、三方库(2)

android 程序员 移动开发

Android Camera 内存问题剖析,Android屏幕适配很难嘛其实也就那么回事

android 程序员 移动开发

Android D8 编译器 和 R8 工具,android零基础开发

android 程序员 移动开发

Android JVM面试专题:阿里100%会问到的c,Android开发工程师面试题

android 程序员 移动开发

Android GreenDao 使用全面讲解(1),2021Android最新大厂面试真题总结

android 程序员 移动开发

Android P 应用兼容常见错误及建议,大牛教你怎么学习Android多进程

android 程序员 移动开发

Android ShapeableImageView使用详解,告别shape、三方库

android 程序员 移动开发

Android Retrofit 2,今天带你详细了解各组件原理

android 程序员 移动开发

Android ShapeableImageView使用详解,告别shape、三方库(1)

android 程序员 移动开发

Android Ashmem匿名共享内存,科学技术协会面试

android 程序员 移动开发

Android Jetpack 之 Lifecycle - 2,2021移动开发者未来的出路在哪里

android 程序员 移动开发

Android SDK 开发应该注意哪些?,阿里+头条+腾讯大厂Android笔试真题

android 程序员 移动开发

Android Glide 3,android编程软件

android 程序员 移动开发

Android mvvm 之 LiveData 的原理,2021年Android高级面试题

android 程序员 移动开发

Android Studio 3,今年Android面试必问的这些技术面

android 程序员 移动开发

Android Socket使用详解,android开发入门与实战作者

android 程序员 移动开发

android Alarm闹钟发送广播播放音乐,【大牛疯狂教学

android 程序员 移动开发

Android MediaPlayer音频播放器详解,字节跳动高工面试

android 程序员 移动开发

Android O 适配详细指南,Android开发三年月薪才12K

android 程序员 移动开发

Android Handler 从使用到进阶,html5手机端开发

android 程序员 移动开发

Android Studio 4(1),android面试必看书籍

android 程序员 移动开发

Android Glide 3(1),撸了郭霖大神写的Framework源码笔记

android 程序员 移动开发

Android Gradle 干货,android屏幕适配框架

android 移动开发

Android Gradle进阶配置指南,太爽了

android 程序员 移动开发

Android GreenDao 使用全面讲解,android开发教程百度网盘

android 程序员 移动开发

Android Matrix矩阵,跨平台移动开发ui

android 程序员 移动开发

android activity Intent 传值 传对象,移动智能终端的发展趋势

android 程序员 移动开发

Android App安装包大小优化,Android开发面试技能介绍

android 程序员 移动开发

Android DataBinding 从入门到进阶,android路由实现

android 程序员 移动开发

Android Sqlite数据库升级时注意事项,android移动开发基础题库

android 程序员 移动开发

依赖注入是否值得?_.NET_Niclas Nilsson_InfoQ精选文章