翻译:Why use dependency injection
原文来自:Why use dependency injection
第一次翻译,如有问题还请留言指出。
E-mail:root@kaaaaai.cn
为什么使用依赖注入?
本文档介绍了依赖注入的基本知识;它是什么;以及为什么把它加入进你的应用开发中会是个好的模式?下文将用 DI 这个术语作为依赖注入(dependency injection)的简称。
一个真实的例子来说明
与其用抽象的语言描述这个模式,不如用一个简单的基于视图控制器的例子来理解它。如果你对抽象描述感兴趣,维基百科有一篇很棒的文章。
比如说我们正在开发一个照片浏览应用程序,其中,我们有一个视图控制器(view controller),显示从服务器上获取的一组照片。在这个非常简单的应用中,我们有一个 PhotosViewController
去展示照片,还有一个 PhotosService
封装了从我们的服务器请求照片的逻辑。PhotosViewController
实现了视图逻辑,而 PhotosService
包含 HTTP 请求发送和响应解析逻辑。没有使用 DI 时,我们的 PhotosViewController
会在 init
或 viewDidLoad
方法中实例化一个新的 PhotosService
实例,然后在适合的时候使用服务对象来请求照片。
现在我们回过头来分析一下我们的代码。在当前状态下,PhotosViewController
和 PhotosService
是紧密耦合的。这就给我们留下了一些问题:
- 在不改变
PhotosViewController
的情况下,我们不能改变PhotoServie
。这在只有两个类的情况下似乎没有问题,但在有上百个类的实际场景中,这将大大降低我们的应用迭代速度。 - 在不改变
PhotosViewController
的情况下,我们不能替换掉PhotoServie
。我们想象一下,我们现在有了一个更好的PhotosServiceV2
类,想让我们的视图控制器使用,我们就必须深入研究PhotosViewController
的实现来进行修改。 - 不引用
PhotoServie
我们就无法对PhotosViewController
进行单元测试。 - 我们不能同时独立开发
PhotosViewController
和PhotoServie
。这可能看起来不是很大的问题,但在团队开发的真实环境中,我们的工程师将会不断被阻挠。
让我们加入 DI 模式到我们的应用。使用 DI,我们将会有第三个类,在 Needle 中,它被称作 Componet
类,他的作用是实例化 PhotosService
并通过协议(protocl)传递给 PhotosViewController
使用。我们将此协议(protocol)称为 PhotosServicing
。现在,我们的 PhotosViewController
不再知道任何关于 PhotosService
的具体实现了,它只需使用传入的 PhotosServicing
协议来执行其逻辑。
使用 DI 后,我们再来看看之前的问题:
- 我们可以自由的改变
PhotosService
的实现,而不影响我们的PhotosViewController
。 - 我们可以简单地更新 DI
Component
类,实例化PhotosService
并给PhotosViewController
使用,只要它的实现仍然遵从PhotosServicing
协议。这是我们可以自由切换照片服务(photos service)的实现而无需在视图控制器(view controller)中做任何修改。 - 我们可以通过注入(injecting),也就是传入一个模拟
PhotosServicing
对象来正确地对PhotosViewController
进行单元测试。 - 只要定义了
PhotosServicing
协议,我们就可以同时独立开发PhotosService
和PhotosViewController
的实现。
依赖注入术语
在继续之前,让我们定义一些 DI 模式常用的术语。在上面我们简单的例子中,PhotosService
通常被称为“依赖关系”(dependency),我们的 PhotosViewController
有时称为“依赖”或“消费者”。将 PhotosServicing
的实例传入 PhotosViewController
的行为称为 “注入”。总之,我们简单的 DI 设置将 PhotosServicing
依赖关系注入到消费者 PhotosViewController
中。