iOS — SOLID Principles Pt.5 — Dependency Inversion Principle

Roni Leyes
The Aesthetic Programmer
3 min readApr 15, 2018
Dip — a thick cold sauce for dipping pieces of food into before eating them

DIP — Dependency Inversion Principle, states that:

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should depend on abstractions.

I will try to explain that principle by giving some examples of commonly used implementations and what this principle is stating instead..

Let’s say you have a UITableViewController that displays nearby bluetooth devices. We’ll call it NearbyDevicesViewController.

The VC and its logic is the high-level module and it uses a low-level module from your service layer, a BLEClient or something like that.

A common implementation would be that NearbyDevicesViewController has a property of (and it depends on) BLEClient.

This approach is not flexible at all. Changing the way BLEClient works or changing the property to hold another class might break our NearbyDevicesViewController.

The DIP approach

A better approach would be to use an abstraction of what the NearbyDevicesViewController needs.

We would declare some protocol, DevicesProvider, for example.

That protocol will declare the “contract” between the two. The view controller will hold a property of some type that conforms to that protocol, making it depend on the abstraction(the protocol) and any lower-level module that seeks to help the view controller, will depend on implementing the requirements mentioned in the protocol.

Notice how that goes nice with Liskov Subtitution Princinple, because this “contract” let’s us replace our devices provider with any other subtype without altering our program)

Inversion

This principle tries to invert the conventional approach where high-level modules depend upon low-level modules. High-level modules in this approach own the abstraction(by deciding the methods of the protocol) which the low-level modules then conform to.
Kind of making the lower level dependent on what the higher level modules ask for.

That’s where both lower-level and higher-level modules depend on abstractions(Protocols, in our case), as mentioned above:

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.

Flexibility

In the example with DevicesProvider, we can now enjoy flexibility at it’s best.
For example, if we now want to change our class from the service layer, the BLEClient, to another class from the service layer, GPSClient, we can inject it with dependency injection and as long as it conforms to DevicesProvider and everything should be fine.

Decoupling

Look how we decouple our code here. Instead of having this:

We now have this:

NearbyDevicesViewController is not coupled with BLEClient. Which means we don’t HAVE to use them both together. Each one can be replaced with another, because they now depend on the abstraction and not upon each other.

That’s it. Thanks for being awesome and leave a comment below.
Clap if you liked it :)

--

--