我设法理解依赖注入概念,但我根本不知道依赖性反转发生在哪里。
例如,此类具有严格的依赖关系。
class Man
{
public function eat()
{
$food = new Food();
$food->unpack();
$food->use();
}
}
但是在应用DI概念时,它有点变成了:
class Man
{
public function eat($food)
{
$food->unpack();
$food->use();
}
}
但是,无论情况如何,Man
仍然会Food
依赖,所以我看不到依赖项的反转。
唯一的区别是谁将Food
放在他的桌子上。
所以我要求你告诉我,反演原则在哪里以及如何适用?
答案 0 :(得分:1)
该模式被称为"依赖注入",而不是"依赖性反转"。所以是的,仍然存在依赖性。但不同之处在于,这种依赖性是从外部注入的,而不是从内部创建或查找的。 p>
该模式也被称为"控制反转"。为什么?因为该类没有控制API /框架来获取其依赖性。相反,框架是控制组件相互创建和注入的框架。
这个问题的答案很重要:你能否轻松地使用假依赖(Food
实例)来对组件进行单元测试(Man
这里)。答案在第二个片段中是肯定的,但在第一个片段中没有答案:
var food = new FakeFood();
var man = new Man(food);
man.eat();
// now you can check that FakeFood.unpack() and FakeFood.use() have been called.
答案 1 :(得分:1)
请注意,DI是遵循DIP原则的方式。
一个简单的例子来理解"反转的概念"是采用静态语言,如Java。
如果没有应用DIP,您将拥有:
public class CarStarter {
public start() {
new Ferrari().start();
}
}
如果我们想要Ferrari
更改Porsche
,我们必须打破课程。
我们说" CarStarter" 取决于一个低级别的项目:Ferrari
。
所以DIP prones:"我不希望CarStarter
依赖于汽车的特定性质,我希望汽车依赖于CarStarter
!&#34; < / p>
那么在这种情况下满足此要求的简单解决方案是什么?
=&GT;使CarStarter依赖于接口(Car
)而不是具体元素
CarStarter
期望接口,因此Ferrari
必须实现它。
这就是为什么我们谈论&#34;倒置&#34;:
以前,Ferrari
是&#34;免费&#34;任何要实施的规则
但是现在Ferrari
应该遵循一些规则,在这种情况下&#34;实现Car
接口&#34;。
这样,您就可以让CarStarter
无视其使用的具体类:
public class CarStarter {
public start(Car car) {
car.start();
}
}
请注意,这种做法确实简化了CarStarter
类的测试,因为您可以存根/模拟Car
。
这里是Bob叔叔的摘录(DIP原则的作者):
有人可能会质疑为什么我使用“反转”这个词。坦率地说,确实如此 因为比较传统的软件开发方法,比如 结构化分析和设计,倾向于创建软件结构 哪些高级模块依赖于低级模块,其中 抽象取决于细节。确实是这些目标之一 方法是定义描述如何的子程序层次结构 高级模块调用低级模块。图1是一个 这种层次结构的好例子。因此,一个的依赖结构 精心设计的面向对象程序相对于“倒置” 通常由传统结果产生的依赖结构 程序方法。
因此,总结一下:
这个词的倒置来自于DIP原则的目的是反向&#34;开发者的习惯:
抽象不应取决于细节 细节应取决于抽象。