user2699477
user2699477

Reputation:

Is the dependency inversion principle really present in the context of a DI system?

I managed to understand the dependency injection concept, but I simply don't see where the dependency inversion takes place.

For example, this class has tight dependencies.

class Man
{
    public function eat()
    {
        $food = new Food();
        $food->unpack();
        $food->use();
    }
}

But when applying the DI concept it kinda turns into this:

class Man
{
    public function eat($food)
    {
        $food->unpack();
        $food->use();
    }
}

However, whatever the case would be, the Man will still depend on Food, so I see no inversion of dependencies here.

The only difference is who puts Food on his table.

So I'm asking you to make it clear for me, where and how is the inversion principle applied?

Upvotes: 0

Views: 109

Answers (2)

Mik378
Mik378

Reputation: 22191

Note that DI is A WAY to follow DIP principles.

A simple example to understand the concept of "inversion" is to take a static language, like Java.

With no DIP applied, you would have:

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

Here, we would have to break the class if we want to change the Ferrari by Porsche. We say that "CarStarter" depends on a low-level item: the Ferrari.

So DIP prones: "I do not want the CarStarter to depend on the specific nature of the car, I want the car to depend on the CarStarter !"

So what would be an easy solution to fulfill this requirement in this case?

=> Make the CarStarter depends on an interface (Car) instead of the concrete element.
CarStarter expects the interface, so Ferrari MUST implement it. That's why we talk about "inversion":
Before, Ferrari was "free" of any rules to be implemented.
But nowFerrari is expected to follow some rules, in this case "implementing the Car interface".

This way, you'd let your CarStarter be UNAWARE of the concrete classes it uses:

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

Note that this practice really eases the testing of the CarStarter class, since you could stub/mock the Car.

EDIT -------

Here's an excerpt of Uncle Bob (author of DIP principle):

One might question why I use the word “inversion”. Frankly, it is because more traditional software development methods, such as Structured Analysis and Design, tend to create software structures in which high level modules depend upon low level modules, and in which abstractions depend upon details. Indeed one of the goals of these methods is to define the subprogram hierarchy that describes how the high level modules make calls to the low level modules. Figure 1 is a good example of such a hierarchy. Thus, the dependency structure of a well designed object oriented program is “inverted” with respect to the dependency structure that normally results from traditional procedural methods.

Thus, to sum up:

The word inversion comes from the fact that the DIP principle aims to "inverse" the habits of developers:

Abstraction should not depend upon Details.
Details should depend upon Abstractions.

Upvotes: 1

JB Nizet
JB Nizet

Reputation: 691943

The pattern is called "dependency injection", not "dependency inversion". So yes, there still is a dependency. But the difference is that this dependency is injected from the outside, instead of being created or looked up from the inside.

The pattern is also called "inversion of control". Why? Because the class doesn't control an API/framework to get its dependencies. Instead, the framework is the one which controls the creation and injection of components into each other.

What matters is the answer to this question: can you easily use a fake dependency (Food instance here) in order to unit-test the component (Man here). The answer is yes in the second snippet, but no in the first one:

var food = new FakeFood();
var man = new Man(food);
man.eat();
// now you can check that FakeFood.unpack() and FakeFood.use() have been called.

Upvotes: 1

Related Questions