Dependency Inversion Principle (DIP) Explained

Dependency Inversion Principle stats :


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.


Simply, Depend on Abstractions and not concretes. 

This principle aims at reducing the coupling between different pieces of code.

Why this principle ?

  • Making change in highly coupled code is a risky task. 
  • The same can be simplified by making high level abstraction of your low level details. 
  • High level abstraction can be achieved by creating interface
  • Abstract concepts like logging, caching by creating interface, so even if change happens in any of these concepts, the actual logical code will be unaffected by these changes.

This will be simplified by following example :

Consider we have a service which does some logical operations by getting data from FTP. We also cache and log the FTP data which you receive. In constructor we receive details of FTP connection like host, port, username, password etc. The code works as expected but it does not follow Dependency Inversion principle.



The service directly depends on low level implementation, instead it should depend on high level abstraction according to the principle. So coding wise, we have to move the FTP related stuff to new service, so our main service class is clean.



We will inject the same in our service. Our main service now does only the logical operations which the service is supposed to do.




We have moved the code from our Service to FTPStorage class which makes our code cleaner. However everything is still tightly coupled. If in future we have to replace getting data from FTP to HTTP, then coding the same in our existing system is tough task to implement.

Till now we have just moved the code to new class.

Now we make higher level abstraction by creating an Storage interface and make our FTPStorage class implement this interface.





The data fetching part is written in the get() function which we created.
Now in our Service we inject something which implements that interface. This is called Dependency Inversion. We make higher level abstraction instead of doing lower level implementation.
In here we can have any storage implementation.





Now how to create object of our Service.
We have to create object of FTP which includes hostname, password etc. new Ftp($settings)
Then we have to create FTPStorage class which will get the data. new FtpStorage(new Ftp($settings))
And finally our Service object. new Service( new FtpStorage(new Ftp($settings)))

For new Http fetching data, we change the object creation to
new Service( new HttpStorage(new Http($settings)))
and our logical code remains same.

Thus ensuring loosely coupled design.







Comments

Popular posts from this blog

"Don't Ask, Tell" Principle

GREP Cheatsheet