Home » Php » php – Difference between dependency injection and dependency inversion

php – Difference between dependency injection and dependency inversion

Posted by: admin April 23, 2020 Leave a comment

Questions:

Two design patterns namely Dependency Injection and Dependency Inversion exist out there, Articles are there in the net trying to explain the difference. But the need to explain it in easier words is still there. Any one out there to come up to ?

I need to understand it in PHP.

How to&Answers:

(Note: This answer is language-agnostic, although the question specifically mentions PHP, but being unfamiliar with PHP, I have not provided any PHP examples).

Injection vs Inversion

  • Dependency Injection is an Inversion of Control technique for supplying objects (‘dependencies’) to a class by way of the Dependency Injection Design Pattern. Typically passing dependencies via one of the following:

    • A constructor
    • A public property or field
    • A public setter
  • The Dependency Inversion Principle (DIP) is a software design guideline which boils down to two recommendations about de-coupling a class from its concrete dependencies:

    1. ‘High-level modules should not depend on low-level modules. Both should depend on abstractions.’
    2. ‘Abstractions should not depend upon details. Details should depend upon abstractions.’

Dependency Injection

Firstly, Dependency Injection is not the same thing as Inversion-of-Control (IoC). Specifically, IoC is an umbrella of different solutions, including Dependency Injection, Service Locator, Factory Pattern, Strategy Pattern and others.

A class which is designed with Dependency Injection in mind may look like this:

// Dependency Injection Example...

class Foo {
    // Constructor uses DI to obtain the Meow and Woof dependencies
    constructor(fred: Meow, barney: Woof) {
        this.fred = fred;
        this.barney = barney;
    }
}

In this example, Meow and Woof are both dependencies injected via the Foo constructor.

On the other hand, a Foo class which is designed without Dependency Injection might simply create the Meow and Woof instances itself, or perhaps use some kind of service locator/factory:

// Example without Dependency Injection...

class Foo {
    constructor() {
        // a 'Meow' instance is created within the Foo constructor
        this.fred = new Meow();

        // a service locator gets a 'WoofFactory' which in-turn
        // is responsible for creating a 'Woof' instance.
        // This demonstrates IoC but not Dependency Injection.
        var factory = TheServiceLocator.GetWoofFactory();
        this.barney = factory.CreateWoof();
    }
}

So dependency injection simply means that a class has deferred responsibility of obtaining or providing its own dependencies; instead that responsibility resides with whatever wants to create an instance. (Which is usually an IoC Container)


Dependency Inversion

Dependency Inversion is broadly about de-coupling concrete classes by preventing those classes having any direct reference to each other.

Note: Dependency Inversion is often more explicit in statically typed programming languages such as C# or Java, because those languages enforce strict type-checking on variable names. On the other hand, Dependency Inversion is already passively available in dynamic languages such as Python or JavaScript because variables in those languages do not have any particular type restrictions.

Consider a scenario in a statically typed language where a class requires the ability to read a record from the application’s database:

class Foo {
    reader: SqlRecordReader;

    constructor(sqlReader: SqlRecordReader) {
        this.reader = sqlReader;
    }

    doSomething() {
        var records = this.reader.readAll();
        // etc.
    }
}

In the above example, class Foo has a hard dependency on SqlRecordReader, but the only thing it really cares about is that there exists a method called readAll() which returns some records.

Consider the situation where SQL database queries are separated out into separate microservices; the Foo class would need to read records from a remove service instead. Or alternatively, a situation where Foo unit tests needs to read data from an in-memory store or a flat file.

If, as its name suggests, the SqlRecordReader contains database and SQL logic, any move to microservices would need the Foo class to change.

Dependency Inversion guidelines suggest that SqlRecordReader should be replaced with an abstraction which only provides the readAll() method. i.e:

interface IRecordReader {
    Records[] getAll();
}

class Foo {
    reader: IRecordReader;

    constructor(reader: IRecordReader) {
        this.reader = reader;
    }
}

As per the DIP The IRecordReader is an abstraction, and forcing Foo to depend on IRecordReader instead of SqlRecordReader satisfies DIP guidelines.


Why DIP Guidelines are Useful

The keyword is guideline – dependency inversion adds indirection to the design of your program. The obvious disadvantage of adding any kind of indirection is that the complexity (i.e. the cognitive “load” required for a human to understand what’s going on) increases.

In many cases, indirection can make code easier to maintain (fix bugs, add enhancements) however:

In this last example, Foo might receive a SqlRecordReader, or maybe a SoapRecordReader, or perhaps a FileRecordReader, or maybe even for unit testing a MockRecordReader – the point is that it doesn’t know or care anything about different possible implementations of IRecordReader – provided of course those implementations live up to the Liskov Substitution Principle.

Furthermore, it avoids the potentially dirty scenario where a developer who is in a rush to get something working might consider trying to “fudge” the Liskov principle by inheriting the SoapRecordReader or FileRecordReader from a base class SqlRecordReader.

Worse still, an inexperienced developer might even change the SqlRecordReader itself so that class has logic not only for SQL but also for SOAP endpoints, The Filesystem, and anything else which might be needed. (This kind of thing happens too often in the real world – especially in poorly maintained code, and is nearly always a Code Smell.)

Answer:

See this article here

The author differentiates these two in simple words. Dependency Injection == “Gimme it” and Dependency Inversion == “Someone take care of this for me, somehow.”. In dependency inversion principle, high level module is the owner of the abstraction. Thus the detail(implementation of the abstraction) is depends on the abstraction and hence depends on the high level module. Dependency inverted!.. Dependency injection is different. The abstraction might not be kept by the high level module. Thus an abstraction given to the higher level object might not be limited to the needs of the high level module.

Dependency inversion :

You have a higher level module X and an abstraction Y which is defined by X. Z implements Y and is given to X. Thus Z is dependent of X(via the abstraction Y defined by X).

Dependency injection:

You have an higher level module X which needs functionalities A and B. Y is an abstraction which contains the functionalities A, B and C. Z implements Y. Since Z implements Y and hence have functionalities A and B, Z is given to X. Now X is dependent of Y.

Answer:

Dependency Injection is one way to achieve Inversion of Control (which I am assuming you are referring to as Dependency Inversion), so the two aren’t really in competition as much as DI is a specialization of IoC. Other commonly seen ways to achieve IoC include using factories or the Service Locator pattern.