"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;
}
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;
}
}
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);
}
}
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
Top comments (2)
Which Service Container will know that you have only one implementation of the abstraction?
No one, for that, it’s important that they provide a way to solve it. For example, in Laravel you can use “contextual binding” laravel.com/docs/8.x/container#con...