S.O.L.I.D Principle Inversion of Control and Resolution With Dependency Injection

The S.O.L.I.D principle of OOP has one very important principle named Inversion of Control. In this article I'm sharing my thoughts of Inversion of Control.

For a few days I've been exploring more about design patterns and OOP principles. Kindly visit the following links for Design Pattern and OOP principles.

S.O.L.I.D Principles:

Design Patterns:

Why is Inversion of Control required?

The problem here is tight coupling in classes. In other words, "class A depends on class B". Let's take an example and try to understand the tight coupling.

Suppose we have a Samsung class that contains an Android class object. An issue with this is tight coupling between classes. In other words the Samsung class depends on the Android object. So if the Android class changes for any reason then it may affect the Samsung class.

  1. The problem is that the Samsung class controls the creation of the Android object.
  2. The Android class is directly referenced in the Samsung class that leads to tight coupling among address and customer objects.
  3. If we make any changes to the Android class then it might affect the Samsung class also, because the Samsung class is dependent on the Android class. Suppose that we add some properties or methods to the Android class then it might require changes in the Samsung class.

In easier words, this is called Object Dependency. Object Dependency means that, for one object  to work, it needs another object. In other words one object is dependent on another object.

Here is the code segment for understanding this:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace IOCSample

{

    class Android

    {

        private string strAndriodVersion;

        private int strInternalMemory;

 

        public string propAndriodVersion

        {

            get { return strAndriodVersion; }

            set { strAndriodVersion = value; }

        }

        public int propInternalMemory

        {

            get { return strInternalMemory; }

            set { strInternalMemory = value; }

        }

 

        public Android(string AndriodVersion, int InternalMemory)

        {

            propAndriodVersion = AndriodVersion;

            propInternalMemory = InternalMemory;

        }

    }

 

 

    class Samsung

    {

        private string MobileName;

        private Android Android;

        //private string AndriodVersion;

        //private int InternalMemory;

 

        public Samsung(string strMobileName, string objAndriodVersion, int objInternalMemory)

        {

            Android objAndroid = new Android(objAndriodVersion,objInternalMemory);

 

           this.MobileName = strMobileName;

           this.Android = objAndroid;

            //this.AndriodVersion = objAndriodVersion;

           // this.InternalMemory = objInternalMemory;

           

        }

 

        public override string ToString()

        {

            return string.Format("Mobile Name: {0} Version :{1} having internal memory:{2}", this.MobileName, this.Android.ToString(), this.Android.ToString());

        }

    }

    class Program

    {

        static void Main(string[] args)

        {

            Samsung samsung = new Samsung("Galaxy Grand", "Jelly Bean", 16);

            Console.WriteLine(samsung.ToString());

            Console.ReadLine();

        }

    }

}

Look at the image given below to understand the concept of tight coupling.

SOLID1.jpg

Dependency Injection

To solve the problem of tight coupling here we have an easier and simpler way, "Inversion of Control" (IOC).

In more simple words Inversion of Control could be defined as: "delegation of a task of object's creation to a third party, to do low coupling between objects and to minimize dependency between objects".


There are two points related to IOC:

  1. The main class shouldn't be dependent on another class. Both classes should be dependent on abstraction.

  2. Abstraction could be done through an interface or abstract class.

This is the basic concept for implementing the Inversion of Control (IOC) pattern.

  • It wipes out tight coupling between objects.

  • Makes objects and application more flexible.

  • It facilitates creating more loosely coupled objects and their dependencies.

    SOLID2.jpg

Kindly have a look at the code below to understand the IOC implementation. I am using Constructor Injection.

Here the object reference would be passed to the constructor of the business class Samsung. In this case, since the Samsung class depends on the Android class, a reference of the Android class will pass steps to implement Constructor Injection. I am using a very basic approach for this.

Step 1

 

Create an Interface:
 

interface IMobile

    { }


Step 2

 

Implement an interface to the Android class. An object of the Android class references the Samsung class. See:
 

class Android : IMobile

    {

        private string strAndriodVersion;

        private int strInternalMemory;

 

        public string propAndriodVersion

        {

            get { return strAndriodVersion; }

            set { strAndriodVersion = value; }

        }

        public int propInternalMemory

        {

            get { return strInternalMemory; }

            set { strInternalMemory = value; }

        }

 

        public Android(string AndriodVersion, int InternalMemory)

        {

            propAndriodVersion = AndriodVersion;

            propInternalMemory = InternalMemory;

        }

        public override string ToString()

        {

            return string.Format(" Version :{0} is having internal memory:{1}", this.propAndriodVersion, this.propInternalMemory);

        }

    }


Step 3

 

Make a reference of the interface in the Samsung class:
 

class Samsung

    {

        private string MobileName;

        private IMobile objIMobile;

 

 

        public Samsung(string strMobileName, IMobile obj)

        {

           

            this.MobileName = strMobileName;

            this.objIMobile = obj;

 

        }

        public override string ToString()

        {

            return this.MobileName;

        }

 

    }

Step 4

 

Create a third party class, that creates an instance of all these objects. See:
 

class IOC

    {

        IMobile objMobile = null;

       Samsung samsung;

 

        public void Assembling()

        {

            objMobile = new Android("Jelly Bean", 16);

            samsung = new Samsung("Galaxy Grand", objMobile);

        }

        public override string ToString()

        {

            return string.Format("Mobile Name: {0} and {1}", this.samsung.ToString(), this.objMobile.ToString());

        }           

    }


Step 5

 

Use this third party class at the client side.
 

class Program

    {

        static void Main(string[] args)

        {

            IOC objIOC = new IOC();

            objIOC.Assembling();

            Console.WriteLine(objIOC.ToString());

            Console.ReadLine();

        }

    }

The following is sample output of the preceding codev using constructor injection.

SOLID3.jpg

  • Defects of Constructor Injection
     

  • In constructor injection, the business logic class doesn't have a default constructor. The reason is that we always require passing values as parameterized constructor.

  • Once the class is instantiated, Object Dependency cannot be changed.

The sample application is attached as a reference .This application has code with constructor injection.

Hope you enjoyed the way to understand the IOC.

Keep coding and Enjoy.