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 previous articles we discussed 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 to develop de-coupled architecture.

The following are the rules if the principal:

  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 this with the following simple example.

class Work
{
   public void DoWork()
   {
      Console.Write("I am working");
   }
}
class DeveloperEmployee
{
   Work objWork;
   public void SetWork(Work tmp)
   {
      objWork = tmp;
   }
}

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

So, here is the first principal; 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 the low-level module in the high-level module, that proves a dependency.

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

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net.Http;

using System.Net.Http.Headers;

using System.Text;

using System.Threading.Tasks;

 

namespace EntityFramework

{

    interface IWork

    {

        void DoWork();

    }

    class DeveloperEmployee :IWork

    {

        public void DoWork()

        {

            Console.WriteLine("I am Developer, Working in VS");

        }

    }

    class HREmployee : IWork

    {

        public void DoWork()

        {

            Console.WriteLine("I am HR, Working in VS");

        }

    }

    class MakeWork

    {

        public void CallWorker(IWork tmp)

        {

            tmp.DoWork();

        }

    }

    class Program

    {

        static void Main(string[] args)

        {

            MakeWork objMakeWork = new MakeWork();

            objMakeWork.CallWorker(new DeveloperEmployee());

            objMakeWork.CallWorker(new HREmployee());

            Console.ReadKey();

        }

    }

}


We have created an interface called IWork and two types of employee classes called “DeveloperEmployee” and “HRmployee” In both we have implemented an IWork interface.
Then we are using MakeWork class to call appropriate DoWork() method.

Now, note that we are not creating an object of our concrete class (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 ideas of SOLID in software architecture. I hope you have understood the concept and planning to follow those principles in development. Thanks to all for being with this series. Happy learning.