Understanding Dependency Inversion principle

mguinea

Marc Guinea

Posted on August 10, 2021

Understanding Dependency Inversion principle

"Depend upon abstractions, [not] concretions."

Dependency Inversion is the "D" of the SOLID principles promoted by Robert C. Martin.

There are a lot of articles talking about it, but I want to explain it as easily as possible through an example.

When you create a new service, create first its interface, then implement it in a class.

Example

A service that calculates the average of two numbers.

Interface has the contract that will always be respected

interface AverageCalculator
{
    public function calculate(float $first, float $second): float;
}
Enter fullscreen mode Exit fullscreen mode

Then, the implementation (which can be anything... a call to an external API, package, your own implementation...)

use AverageCalculator;

class InMemoryAverageCalculator implements AverageCalculator
{
    public function calculate(float $first, float $second): float
    {
        return ($first + $second) / 2;
    }
}
Enter fullscreen mode Exit fullscreen mode

When you inject it in a controller, never inject the class, inject the interface. Let Service Container resolve it.

use AverageCalculator;

class Somewhere
{
    private AverageCalculator $calculator;

    public function __construct(AverageCalculator $calculator)
    {
        $this->calculator = $calculator;
    }

    public function __invoke(float $first, float $second): float
    {
        return $this->calculator->calculate($first, $second);
    }
}
Enter fullscreen mode Exit fullscreen mode

Service Container knows what is the implementation (InMemoryAverageCalculator) so we just need to configure it if required.

Benefits

There are several benefits of this approach:

  • You force yourself at first step to define a contract (interface) knowing what you want.
  • You can change the implementation at any time without having to change everywhere it is used.
  • Concretions will not affect to the design of your application because your interface rules the inputs / outputs.

Conclusion

When injecting an interface, you are depending upon an abstraction, you don't set the class that implements that logic but yo define what to expect from that class.

This brings a lot of flexibility and adaptation to changes.

Remember:

Abstraction === Interface
Concretion === Class with implementation

💖 💪 🙅 🚩
mguinea
Marc Guinea

Posted on August 10, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related