依赖注入和依赖注入容器
依赖注入和依赖注入容器
这 依赖注入 是一种有助于避免模块中的硬编码依赖性的模式,使调用者有权更改它们并在他们想要的地方提供自己的。让我们通过一个例子来弄清楚它需要什么:
让我们看一下这个例子,Car 类需要一个 Tires 类的实例。我们可以说汽车依赖于轮胎。正如我们所看到的,这个例子是有效的,轮胎字段在 Car 构造函数中由轮胎类的实例成功初始化。但是,这种方法会导致 问题 .要查看它们,让我们更改轮胎类的实现(例如,添加一个构造函数参数)
我们看到,现在为了正确获取 Car 中的 Tires 类实例,我们需要对 Car 类进行更改。
在更改Tires类时,我们必须找到所有在其他类中使用它的地方并进行更改,非常不方便。
此外,现在要获取 Car 类的实例,我们需要传递的不是 3 个而是 4 个参数。如果你想象 Car 类也可以用在更高级别的模块中——那么一个类的变化可能会导致一系列类似雪崩的变化。
测试 Car 也有困难,不可能替换 Tires 实现,因为它在使用的地方直接硬编码。
事实证明,一个类依赖于另一个类的实现,这违反了 SOLID 原则之一——依赖倒置原则 (DIP)。高级模块不应该依赖于低级模块;两种类型都应该依赖于抽象。
为了解决这个问题,让我们将必要的依赖传递给 Car 类的构造函数的参数。
我们已经传递了一个依赖项(Tires 类的实例)作为 Car 类的构造函数的参数,现在 Car 类的实现不依赖于 Tires。
这种模式称为 依赖注入 .
现在让我们想想,这种方法是否足够?
尽管它很简单,但在大型应用程序中这种方法可能无法扩展。想象一个模块可能有很多依赖,它们可能有自己的依赖。
然后检查依赖关系,匹配它们的类型,正确地并以正确的顺序转移依赖关系成为一项不平凡的任务,随着项目变得更加复杂,其复杂性也会增加。
此外,如果其中一个依赖项发生了变化,那么无论在何处传输,都需要替换它。
考虑这个例子:
要获取 Car 类的实例,我们需要手动创建其所有依赖项的实例,而这些依赖项又具有依赖项。
现在假设我们在应用程序的许多地方创建 Car 实例,我们需要更改其中一个依赖项,然后我们必须找到所有这些地方并手动修复依赖项。
如果某个实体为我们做这件事,创建所有依赖项的实例并注入它们,那就太好了。
为了解决这个问题,我们将使用控制反转 (IoC) 模式——其本质是开发人员将部分权力用于购买外部实体——函数、库或框架。关于 DI,IoC 是我们在描述类时只指定依赖关系。并且这些依赖项的实例的创建由一些外部代码控制,例如, 依赖注入容器 (DIС) 初始化主类的实例时。
让我们创建一个最简单的依赖注入容器:
让我们弄清楚这个依赖注入容器是如何工作的。
'的概念 依赖关系 ' 在这里使用 - 这些是 班级 需要创建其实例,并且 ' 论据 ' - 是 类、对象或原语的实例, 我们作为参数传递给构造函数。
依赖注入容器将依赖项和参数存储在单独的对象中,其中键是构造函数参数的名称,值 this 是类(用于依赖项)和对象或原语(用于参数)。首先,使用 registerDependency 方法,我们传递给
DIC 所有依赖项并使用 setArgument 方法传递所有参数。然后我们调用 get('car') 方法(在我们的例子中,Car 类具有键 'car')。接下来调用getInstance(Car)方法,得到
Car 类的构造函数的参数名称,并且对于每个参数,再次递归调用 get(parametrName) 方法。如果参数名称与参数匹配,则该方法返回此参数的值。如果参数名称与依赖项匹配,则再次调用该方法 getInstance(dependency) 创建一个依赖项实例并将其作为参数传递。
让我们创建一个依赖注入容器实例并在其中注册所有需要实例化的依赖项,它们将永久存储在容器中并且不需要修改。
现在,在获取 Car 实例的代码中的任何地方,我们将必要的参数传递给依赖注入容器并调用 get() 方法,指定我们要创建的类的实例。
结果将与手动传输依赖项时相同。要获得另一辆车,您只需重置参数并将新参数传递给 DIC,依赖关系保持不变。
现在让我们更改依赖关系,而不是我们使用 Driver 类的 Person 类。
用DIC很容易做到这一点,更换就足够了
dic.register Dependency('person', Person);
上 dic.register Dependency('person', Driver);
并且在应用程序中创建的所有汽车都将自动接收新的依赖项。
当然,这个依赖注入容器并没有解决依赖注入的所有问题,只是展示了基本原理。
我希望这篇文章对你有用。感谢关注!
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明