Dependency Inversion Principal

Demystify SOLID: D for “Dependency Inversion Principal”

Welcome to the Demystify SOLID article series. In this series we are talking about SOLID principals in software design. In our previous articles we discussed our important principles of SOLID, you can read them here.

In this article we will discuss the last principal called “Dependency Inversion Principal”. This is one of the important principals for developing de-coupled architecture.

The principal is saying the following rules.

1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
2. Abstractions should not depend upon details. Details should depend upon abstractions.

Let's understand with a simple example.

  1. class Work  
  2. {  
  3. public void DoWork()  
  4. {  
  5. Console.Write("I am working");  
  6. }  
  7. }  
  8. class DeveloperEmployee  
  9. {  
  10. Work objWork;  
  11.   
  12. public void SetWork(Work tmp)  
  13. {  
  14. objWork = tmp;  
  15. }  

 

That example is pretty simple to look at but full of problems. We are instantiating a Work object within a “DeveloperEmployee” object. That will restrict us from implementation of a de-coupled architecture and it's a sign of a bad design pattern.

So, here the first principal is that a high-level module should not depend on a low-level module. In this example the high level module is “DeveloperEmployee” and the low-level module is “work” and we are creating an object of a low-level module in a high-level module, which proves dependency.

To solve the problem we will use abstraction (as recommended). Here is a simple implementation.

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Net.Http;  
  5. using System.Net.Http.Headers;  
  6. using System.Text;  
  7. using System.Threading.Tasks;  
  8.   
  9. namespace EntityFramework  
  10. {  
  11. interface IWork  
  12. {  
  13. void DoWork();  
  14. }  
  15. class DeveloperEmployee :IWork  
  16. {  
  17. public void DoWork()  
  18. {  
  19. Console.WriteLine("I am Developer, Working in VS");  
  20. }  
  21. }  
  22. class HREmployee : IWork  
  23. {  
  24. public void DoWork()  
  25. {  
  26. Console.WriteLine("I am HR, Working in VS");  
  27. }  
  28. }  
  29. class MakeWork  
  30. {  
  31. public void CallWorker(IWork tmp)  
  32. {  
  33. tmp.DoWork();  
  34. }  
  35. }  
  36. class Program  
  37. {  
  38. static void Main(string[] args)  
  39. {  
  40. MakeWork objMakeWork = new MakeWork();  
  41. objMakeWork.CallWorker(new DeveloperEmployee());  
  42. objMakeWork.CallWorker(new HREmployee());  
  43. Console.ReadKey();  
  44. }  
  45. }  

 

We have created an interface called IWork and two types of employee classed called “DeveloperEmployee” and “HRmployee”. In both we have implemented an IWork interface.

Then we are using the MakeWork class to call an appropriate DoWork() method.

Now, notice that we are not creating an object of our concrete classes (DeveloperEmployee and HREmployee) within the MakeWork class. We are calling the appropriate function using an interface. Here is sample output.

 

Conclusion:

In this article we have covered the fundamental idea of SOLID in software architecture. I hope you have understood the concept and are planning to follow those principles in development. Thanks to all for being with this series. Happy learning.