Dependency Inversion Principle

The Dependency Inversion Principle, sometimes abbreviated as “DIP,” was created by Uncle Bob Martin.

"Depend upon abstractions, not concretes."

The principle has two main point:

  • A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
  • B. Abstractions should not depend upon details. Details should depend upon abstractions.

Dependency Inversion, Dependency Injection and Inversion of Control

Yes, those three are related but are not the same. Dependency Injection is how an object knows about a dependency, Dependency Inversion is how abstract are the methods your method is calling, and Inversion of Control is about who initiates the execution of a method.

Let's see some examples of each one.

Dependency Injection

There are 3 types of dependency injection. Constructor injection, Property injection and Method injection.

Constructor Injection


    public class ChildDrink {
        public void Drink() 
        {
            // Here the drinking takes place
        }
    }

    public class Child 
    {
        protected ChildDrink _drink;

        public Child(ChildDrink drink)
        {
            _drink = drink;
        }

        public void ImThirsty() 
        {
            _drink.Drink();
        }
    }

    static void Main(string[] args)
    {
        Child Mickey = new Child(new ChildDrink());

        Mickey.ImThirsty();
    }
                    
                

As you see, the drink dependency get's injected into the child via the child's constructor. The ImThirsty method will use the injected dependency.

Property Injection (also known as Setter injection)


    public class ChildDrink {
        public void Drink() 
        {
            // Here the drinking takes place
        }
    }

    public class Child 
    {
        public ChildDrink drink;

        public Child()
        {
        }

        public void ImThirsty() 
        {
            _drink.Drink();
        }
    }

    static void Main(string[] args)
    {
        ChildDrink chocolateMilk = new ChildDrink();
        Child Mickey = new Child();
        Mickey.drink = chocolateMilk;
    }



                    
                

In this case the drink (chocolateMilk) is injected using the public drink property of the child. This is generallly used when we need a parameterless constructor.

Method Injection


    public class ChildDrink {
        public void Drink() 
        {
            // Here the drinking takes place
        }
    }

    public class Child 
    {
        public ChildDrink drink;

        public Child()
        {
        }

        public void InjectDrink(ChildDrink drink)
        {
            _drink = drink;
        }

        public void ImThirsty() 
        {
            _drink.Drink();
        }
    }

    static void Main(string[] args)
    {
        ChildDrink chocolateMilk = new ChildDrink();
        Child Mickey = new Child();
        Mickey.InjectDrink(chocolateMilk);
    }

                    
                

In this case the drink (chocolateMilk) is injected using the public method (InjectDrink) of the child.

Dependency Inversion

Remember, Dependency Inversion is how abstract are the methods your method is calling.

The wrong way


    public class Device
    {
        public void TurnOn() 
        {
            // Turn on here
        }
        public void TurnOff() 
        {
            // Turn off here
        }
    }

    public class DeviceManager 
    {
        internal Device device =  new Device();

        public void DoManagement() 
        {
            // let's turn on

            device.TurnOn();

            // let's turn off

            device.TurnOff();
        }
    }
                        
                    

In this example, the DeviceManager class depends directly from a concrete Device class. If the Device class changes, the DeviceManager will also have to change.

The right way


    public interface IDevice 
    {
        void TurnOn();

        void TurnOff();
    }
    public class Device
    {
        public void TurnOn() 
        {
            // Turn on here
        }
        public void TurnOff() 
        {
            // Turn off here
        }
    }

    public class DeviceManager 
    {

        public void DoManagement(IDevice device) 
        {
            // let's turn on

            device.TurnOn();

            // let's turn off

            device.TurnOff();
        }
    }
                        
                    

In this case, the DeviceManager class has no idea what type of Device is being receive, and actually, it does not care what it does. If the Device class changes, the DeviceManager will also have to change.

Now you can easily define a new a new type of device and send it to the DeviceManager...just please, just don't make the new Device nuclear.

Inversion of Control


public interface IEvent
{
    void RunEvent();
}
class College
{
    private IEvent _events = null;
    EventLocator el = new EventLocator();

    public College(int index)
    {
        this._events = el.LocateEvent(index);
    }

    public void DoEvent()
    {
        _events.RunEvent();
    }
}

class FootballEvent : IEvent
{
    public void RunEvent()
    {
        // Go Marlins!
    }
}

class PartyEvent : IEvent
{
    public void RunEvent()
    {
        // Let's drink!
    }
}

public class TechEvent : IEvent
{
    public void RunEvent()
    {
        // Booring...yaawnnn
    }
}

class EventLocator
{
    public IEvent LocateEvent(int index)
    {
        if (index == 1)
            return new FootballEvent();
        else if (index == 2)
            return new PartyEvent();
        else
            return new TechEvent();
    }
}
class Program
{
    static void Main(string[] args)
    {
        College college = new College(1);

        college.DoEvent();
    }
}

In this example, you can see that the College class will delegate the creation of the event to the EventLocator class, and then when the DoEvent methods get's called, invert the control the created event. Nice, right?