Dependency Injection (DI) and Inversion of Control (IOC)

Introduction

Sometimes it becomes very tough to understand the concepts. But they are very easy, and we use them in our daily coding.

Today, I would like to talk about the problem of dependency in coding and what Inversion of Control (IOC) and Dependency Injection (DI) want to say about it. This article is intended for the audience keen to know about one of the essential principles but is confused about implementation.

Agenda

  • What is Inversion of Control (IOC)?
  • What is Dependency Injection (DI)?
  • Ways of achieving Dependency Injection
  • Advantages of implementing this principle

What is Inversion of Control (IOC)?

We all have seen our college days, right?

Sometimes events are being organized in college, and occasionally boring lectures :(. Just considering and remembering our college days, let's relate the College and Events with Inversion of Control (IOC).

Inversion of Control

Suppose I have a class, say College, and another type, says TechEvents. As you can see in the preceding figure, many problems may arise:

  1. Both classes are tightly coupled with each other. I cannot have a College without TechEvents because a TechEvents object is created in a College Constructor.
  2. If I make any changes to TechEvents, I need to compile, or you can say update College too.
  3. College controls the creation of Events. College is aware of the single event that is organized. Suppose there is any specific event to be organized like Weekend FootballEvent or PartyEvent. In that case, a College class needs to be changed as College directly refers to Events.

Now I need to solve this problem somehow; otherwise, we would not be able to have any other events in college.

The solution could be to shift the control of the event's organization to some other place. This we call Inversion of Control (IOC), inverting the control to another entity instead of directly organizing the event in College.

What does the Inversion of control principle say?

Don't Call Me; we will call you.

In other words, the Main class should not have a concrete implementation of an aggregated class, rather, it should depend on the abstraction of that class. The College class should depend on TechEvents class abstraction using an interface or abstract class.

What is Dependency Injection?

IOC can be done using Dependency Injection (DI). It explains how to inject concrete implementation into a class using abstraction, in other words, an interface inside. The main idea of dependency injection is to reduce the coupling between classes and move the binding of abstraction and concrete implementation out of the dependent class.

In Simple words, DI is how one object knows about another abstracted dependent object.

There are mainly four ways of achieving Dependency Injection.

Injection via Constructor

This methodology is already discussed above, where the object of the concrete class is passed to the constructor of the dependent class.

class College  
{  
        private IEvent _events;  
        public College(IEvent ie)  
        {  
            _events = ie;  
              
        }  
  
       public void GetEvents()  
        {  
            this._events.LoadEventDetail();  
        }  
  
} 

As you can see above, the constructor injects the event object, keeping it loosely coupled. The College class will do its work, and if it wants to get the events-related details, it will call it in the constructor based on which event it wants to call.

College coll = new College(new FootballEvent()); 

Along with this advantage, another advantage is that if there are any changes in events or added more events, then College doesn't need to care about that.

Injection via Property

This is the most commonly used methodology where we inject the concrete class by creating a property whose type is the interface.

class College  
{  
        private IEvent _events;  
        public IEvent MyEvent  
        {  
            set  
            {  
                _events = value;  
            }  
        }  
} 

As you can see above, the setter of the MyEvent property will take a concrete object and bind it to the interface. My class is loosely coupled with a concrete object. Any changes to any Event class will not affect my College class.

College coll = new College();  
coll.MyEvent = new FootballEvent(); 

Injection via Method

This methodology passes the concrete class object through the method parameter to the dependent class.

class College  
{  
        private IEvent _events;  
        public void GetEvent(IEvent myevent)  
        {  
            this._events = myevent;  
              
        }  
} 

As you can see above, I have called the event of college using the GetEvents() method, where the type of event is passed as a parameter of an abstract type. This will help me to add or make changes to events without affecting the College; in other words, both are decoupled. This is what I can call the method.

College coll = new College();  
coll.GetEvent(new FootballEvent()); 

Injection via Service Locator

A service locator can act like a simple runtime mapper. This allows code to be added at runtime without re-compiling the application and sometimes without restarting it.

class College  
    {  
        private IEvent _events = null;  
        EventLocator el = new EventLocator();  
        public College(int index)  
        {  
            this._events = el.LocateEvent(index);  
        }  
    }  
  
    class EventLocator  
    {  
        public IEvent LocateEvent(int index)  
        {  
            if (index == 1)  
                return new FootballEvent();  
            else if (index == 2)  
                return new PartyEvent();  
            else  
                return new TechEvents();  
        }  
   } 

The code snippet above shows an EventLocator class between the Events and College that helps us locate the service without knowing the concrete type. Hence any changes to EventLocator will not affect the College class. I am just passing the index value in the constructor that, in turn, calls the third party to locate the event and return it to the constructor.

College coll = new College(1);  
coll.GetEvents(); 

Advantages of implementing this principle

  • It helps in class decoupling.
  • Due to decoupling, the reusability of the code is increased.
  • Improved code maintainability and testing.

Conclusion

Inversion of control (IOC) talks about who will initiate the call, whereas Dependency Injection (DI) talks about how one object acquires dependency on another object through abstraction. I hope you like this article. Please comment on it, whether it's good or bad. Your comment will help me to improve. Thank you. Sharing is valuable no matter what :)

 Refer to the video by Shivprasad Koirala, which may clear your doubt in a better way

https://www.facebook.com/photo.php?v=690253231015623&set=vb.341019362605680&type=2&theater 

References