Skip to main content

Dependency Inversion Principle

· 3 min read
Anton Ilinykh

The Dependency Inversion Principle is the last one from SOLID stands for decoupling the system into independent modules. It means that one part of a system should not depend on another one directly.

Let's see an example.

On the one hand, we have a ViewController which is the part of UI/Presentation Module, and on the other hand, we have some data source which can be a part of Networking/Persistence Module. Let's say it is an URLSession object.

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

URLSession.shared.dataTask(with: url) { data, response, error in
// Do something with response
}.resume()
}

}

This code can be represented by a diagram

The UIViewController depends on URLSession concrete implementation. And it means that URLSession can't be replaced with another Network client such as Alamofire without changing the Presentation Module.

Solution

This problem can be solved with Dependency Inversion just by adding another abstraction between concrete implementations. Some protocol that can live in Presentation Module and the Network Module can conform to it.

and the code above will transform to

protocol HTTPClient {
func load(url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> Void)
}

class ViewController: UIViewController {

var client: HTTPClient!

override func viewDidLoad() {
super.viewDidLoad()

client.load(url: url) { (data, response, error) in
// Do something
}
}
}

Now you can have two separate implementations of HTTPClient protocol, and they both can live in Network Module

That's the way you invert the dependencies from one module to another, and now you can easily switch between two concrete implementations of HTTPClient from Networking Module.