0

我设法理解了依赖注入的概念,但我根本看不到依赖反转发生在哪里。

例如,这个类具有紧密的依赖关系。

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

所以我请你给我说清楚,倒置原则在哪里以及如何应用?

4

2 回答 2

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.
于 2014-08-10T13:02:19.300 回答
1

请注意,DI 是遵循 DIP 原则的一种方式。

理解“反转”概念的一个简单示例是采用静态语言,例如 Java。

如果没有应用 DIP,您将拥有:

public class CarStarter {
    public start() {
       new Ferrari().start();       
    }
}

在这里,如果我们想改变Ferrariby ,我们将不得不打破类Porsche。我们说“CarStarter”依赖于一个低级项目:Ferrari.

所以 DIP 倾向于:“我不想CarStarter依赖于汽车的具体性质,我希望汽车依赖于CarStarter!”

那么在这种情况下,满足此要求的简单解决方案是什么?

=> 使 CarStarter 依赖于接口 ( Car) 而不是具体元素。
CarStarter需要接口,所以Ferrari必须实现它。这就是我们谈论“倒置”的原因:
之前,Ferrari“自由”没有任何要实施的规则。
但现在Ferrari预计会遵循一些规则,在这种情况下“实现Car接口”。

这样,您就CarStarter不会意识到它使用的具体类:

public class CarStarter {
        public start(Car car) {
           car.start();       
        }
    }

请注意,这种做法确实简化了CarStarter类的测试,因为您可以存根/模拟Car.

编辑 - - - -

这是鲍勃叔叔(DIP原理的作者)的摘录:

有人可能会质疑我为什么使用“反转”这个词。坦率地说,这是因为更传统的软件开发方法,例如结构化分析和设计,倾向于创建高级模块依赖于低级模块,抽象依赖于细节的软件结构。实际上,这些方法的目标之一是定义描述高级模块如何调用低级模块的子程序层次结构。图 1 是这种层次结构的一个很好的例子。因此,设计良好的面向对象程序的依赖结构相对于通常由传统过程方法产生的依赖结构是“倒置的”。

因此,总结一下:

倒置一词源于 DIP 原则旨在“倒置”开发人员的习惯:

抽象不应该依赖于细节。
细节应该取决于抽象。

于 2014-08-10T13:22:19.170 回答