依赖倒置原则是否真的出现在DI系统的背景下?

时间:2014-08-10 12:29:17

标签: design-patterns dependency-injection design-principles dependency-inversion

我设法理解依赖注入概念,但我根本不知道依赖性反转发生在哪里。

例如,此类具有严格的依赖关系。

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放在他的桌子上。

所以我要求你告诉我,反演原则在哪里以及如何适用?

2 个答案:

答案 0 :(得分:1)

该模式被称为"依赖注入",而不是"依赖性反转"。所以是的,仍然存在依赖性。但不同之处在于,这种依赖性是从外部注入的,而不是从内部创建或查找的。

该模式也被称为"控制反转"。为什么?因为该类没有控制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:&#34;我不希望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;开发者的习惯:

抽象不应取决于细节 细节应取决于抽象。