0

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?

Dave Schweisguth
  • 36,475
  • 10
  • 98
  • 121

2 Answers2

1

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.
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
1

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.

Mik378
  • 21,881
  • 15
  • 82
  • 180
  • I disagree. With your definition, you would still have dependency injection if the CarStarter called a CarFactory to get an instance of Car. Dependency injection is about injecting dependencies, not about depending on interfaces rather than concrete classes. BTW, there is no dependency between a Car and a CarStarter in your example. – JB Nizet Aug 10 '14 at 13:26
  • 1
    @JBNizet Yes, that's why I specifiy: "A simple example" and not "In all cases DI application is what follows".. – Mik378 Aug 10 '14 at 13:28
  • @JBNizet "BTW, there is no dependency between a Car and a CarStarter in your example" => when I did `new Ferrari()`, it was creating a dependency between the car (not `Car` in term of Interface) and the `CarStarter`. BTW, depending on interface is one of the multiple solutions to keep DI. Factories for instance would be other one. – Mik378 Aug 10 '14 at 13:29
  • 1
    You said: "I want the car to depend on the CarStarter". And the example which follows doesn't show any dependency between Car and CarStarter. Where does Car use a CarStarter? It doesn't. And it shouldn't. There is no inversion of dependency at all. What is inverted is the "control" (hence the term *Inversion of Control*): the DI framework controls the instantiation and wiring of the components, instead of the components controlling the framework to get their dependencies. That's where inversion is. – JB Nizet Aug 10 '14 at 13:35
  • The fact that Ferrari would declare: `implements Car` IS the inversion. Inversion meaning, I expect you to based your code on the target: `CarStarter expecting a Car`, rather than CarStarter based directly on you (Ferrari). – Mik378 Aug 10 '14 at 13:36
  • Nope, that's not what dependency injection is. That's polymorphism, not dependency injection. dependency injection is about dependencies, and injection. Not about implementing interfaces. – JB Nizet Aug 10 '14 at 13:37
  • 1
    I didn't evoke the terme "injection" but "inversion" ;) That's not the same concept IMO. – Mik378 Aug 10 '14 at 13:38
  • Here's a good article about the idea: http://lostechies.com/derickbailey/2011/09/22/dependency-injection-is-not-the-same-as-the-dependency-inversion-principle/ – Mik378 Aug 10 '14 at 13:42
  • 1
    The problem is that the acronym **DI**, that you use in your answer, and that the OP wants to clarify, means dependency **injection**. Not **inversion**. Read https://github.com/google/guice/wiki/Motivation for what dependency injection is. – JB Nizet Aug 10 '14 at 13:43
  • 1
    Indeed, you're right :) The correct term is **DIP**: http://en.wikipedia.org/wiki/SOLID_(object-oriented_design). Updating my answer. – Mik378 Aug 10 '14 at 13:44
  • @JBNizet I already understood the concept of DI(dependency **injection**). But some dude who was explaining this said that in the context of DI, DIP(dependency **inversion** principle) is also present. I have also found out (later on) that the principle of inversion of **control** is also present here, and I really got the idea and its logic. My question was related to DIP and wether or not it is **real** when applying DI (injection). So in a way, Mik378 is right when trying to explain DIP to me. –  Aug 10 '14 at 14:40
  • @JBNizet But at the same time, you are also right and I agree with you when saying that DIP is not really inverting any dependencies. That is exactly what I was thinking of. That, while `car` will need to **implement** the interface, it will not **depend** on nor use the CarStarter. I mean, you could easily instantiate `car` separately and it would behave normally. –  Aug 10 '14 at 14:42
  • @Andrei The article I linked just above well explains that the inversion applies when `CarStarter` needs to change the `Car` interface for its need. **The Ferrari depends on the Car interface needs that are stemmed from the `CarStarter` needs.** The `Ferrari` is "forced" to follow the new interface rules since the CarStarter is the `master` of the coupling rules. To enforce the sensation of inversion, as the article evokes, you would have the `CarStarter` and the `Car` interface in the same module. `Ferrari` would be external and therefore you would notice the inversion mechanism more easily. – Mik378 Aug 10 '14 at 14:47
  • The `Ferrari` is forced to follow the new interface, yes. But only if it needs to be started by `CarStarter`. If you decide to do something else with the car, it would be alright. You could just as well have another "master" like `CarFixer`and only fix the car, not start it. So `Ferrari` will depend on `CarStarter`'s **rules** only if they interconnect, but generally speaking, `CarStarter` is not a vital instance which `Ferrari` needs to **exist**, or is it? –  Aug 10 '14 at 14:55
  • In general, the existence of the `Car` is initially driven by the need of your high-level component, in this case the heart of the logic: the `CarStarter`. Specifically when practicing TDD, I would not create a `Car` before a higher-level component expects it. You shouldn't reason by the fact that the concrete `Car` is independent of the current logic of your application. IMHO. Otherwise, it would be easy to say : "but in case where any code instantiate any concrete `Car`, `Car` would not depend on anything" => I'd create `Car`/`Ferrari` BECAUSE `CarStarter` needs it. – Mik378 Aug 10 '14 at 14:57
  • Maybe we understand something else when it comes to the word "dependency". I understand that if A depends on B, then without B, the A could not exist/behave correctly. In my opinion, it doesn't matter if I don't have a logical reason to instantiate `Car` on the spot. I just do it, and if it works even it being isolated from other components, I will believe that it has no dependencies. –  Aug 10 '14 at 14:57
  • IMO, you should associate "dependency" with "impacted component", not with the "essence of component". – Mik378 Aug 10 '14 at 15:03
  • https://docs.google.com/file/d/0BwhCYaYDn8EgMjdlMWIzNGUtZTQ0NC00ZjQ5LTkwYzQtZjRhMDRlNTQ3ZGMz/edit?hl=en Page 5 should clarify the whole. – Mik378 Aug 10 '14 at 15:07
  • I'm in my application, I need my cars to start, in order for them to start they need to use `CarStarter` so they do depend on `CarStarter`. Is that what you are trying to say? If so, then the cars are conceptually depending on `CarStarter`, but not literally (because they can be externally instantiated). So here comes the question, dependency injection is about conceptual or literal dependencies? Oh, God, it's getting complicated... –  Aug 10 '14 at 15:09
  • Nope, you should say this: " In my application, I have a module aiming to start some cars. I want this module to be reusable whatever the nature of the car is. So I DON'T want `CarStarter` to depend upon Details (instantiate directly `Ferrari`), but the inverse." I updated my post with an excerpt of Uncle Bob. – Mik378 Aug 10 '14 at 15:15
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/59050/discussion-between-andrei-pham-and-mik378). –  Aug 10 '14 at 15:17