Wednesday, August 6, 2014

Dependency Injection

Now that we know the dependency inversion principle and have seen the inversion of control methodology for implementing the dependency inversion principle, Dependency Injection is mainly for injecting the concrete implementation into a class that is using abstraction i.e. 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.
Dependency injection can be done in three ways.
  1. Constructor injection
  2. Method injection
  3. Property injection

Constructor Injection 


In this approach we pass the object of the concrete class into the constructor of the dependent class. So what we need to do to implement this is to have a constructor in the dependent class that will take the concrete class object and assign it to the interface handle this class is using. So if we need to implement this for our AppPoolWatcher class:

class AppPoolWatcher
{
    // Handle to EventLog writer to write to the logs
    INofificationAction action = null;

    public AppPoolWatcher(INofificationAction concreteImplementation)
    {
        this.action = concreteImplementation;
    }

    // This function will be called when the app pool has problem
    public void Notify(string message)
    {   
        action.ActOnNotification(message);
    }
}

In the above code, the constructor will take the concrete class object and bind it to the interface handle. So if we need to pass the EventLogWriter's concrete implementation into this class, all we need to do is

EventLogWriter writer = new EventLogWriter();
AppPoolWatcher watcher = new AppPoolWatcher(writer);
watcher.Notify("Sample message to log");

Now if we want this class to send email or sms instead, all we need to do is to pass the object of the respective class in the AppPoolWatcher's constructor. This method is useful when we know that the instance of the dependent class will use the same concrete class for its entire lifetime.

Method Injection


In constructor injection we saw that the dependent class will use the same concrete class for its entire lifetime. Now if we need to pass separate concrete class on each invocation of the method, we have to pass the dependency in the method only.

So in method injection approach we pass the object of the concrete class into the method the dependent class which is actually invoking the action. So what we need to do to implement this is to have the action function also accept an argument for the concrete class object and assign it to the interface handle this class is using and invoke the action. So if we need to implement this for our AppPoolWatcher class:

class AppPoolWatcher
{
    // Handle to EventLog writer to write to the logs
    INofificationAction action = null;

    // This function will be called when the app pool has problem
    public void Notify(INofificationAction concreteAction, string message)
    {
        this.action = concreteAction;
        action.ActOnNotification(message);
    }
}

In the above code the action method i.e. Notify will take the concrete class object and bind it to the interface handle. So if we need to pass the EventLogWriter's concrete implementation into this class, all we need to do is

EventLogWriter writer = new EventLogWriter();
AppPoolWatcher watcher = new AppPoolWatcher();
watcher.Notify(writer, "Sample message to log");

Now if we want this class to send email or sms instead, all we need to do is to pass the object of the respective class in the AppPoolWatcher's invocation method i.e. Notify method in the above example. 

Property Injection


Now we have discussed two scenarios where in constructor injection we knew that the dependent class will use one concrete class for the entire lifetime. The second approach is to use the method injection where we can pass the concrete class object in the action method itself. But what if the responsibility of selection of concrete class and invocation of method are in separate places. In such cases we need property injection.

So in this approach we pass the object of the concrete class via a setter property that was exposed by the dependent class. So what we need to do to implement this is to have a Setter property or function in the dependent class that will take the concrete class object and assign it to the interface handle this class is using. So if we need to implement this for our AppPoolWatcher class:

class AppPoolWatcher
{
    // Handle to EventLog writer to write to the logs
    INofificationAction action = null;

    public INofificationAction Action
    {
        get
        {
            return action;
        }
        set
        {
            action = value;
        }
    }

    // This function will be called when the app pool has problem
    public void Notify(string message)
    {   
        action.ActOnNotification(message);
    }
}

In the above code the setter of Action property will take the concrete class object and bind it to the interface handle. So if we need to pass the EventLogWriter's concrete implementation into this class, all we need to do is

EventLogWriter writer = new EventLogWriter();
AppPoolWatcher watcher = new AppPoolWatcher();
// This can be done in some class
watcher.Action = writer;

// This can be done in some other class
watcher.Notify("Sample message to log");

Now if we want this class to send email or sms instead, all we need to do is to pass the object of the respective class in the setter exposed by AppPoolWatcher class. This approach is useful when the responsibility of selecting the concrete implementation and invoking the action are done in separate places/modules. 

In languages where properties are not supported, there is a separate function to set the dependency. This approach is also known as setter injection. The important thing to note in this approach is that there is a possibility that someone has created the dependent class but no one has set the concrete class dependency yet. If we try to invoke the action in such cases then we should have either some default dependency mapped to the dependent class or have some mechanism to ensure that application will behave properly.

A Note on IoC Containers


Constructor injection is the mostly used approach when it comes to implementing the dependency injection. If we need to pass different dependencies on every method call then we use method injection. Property injection is used less frequently.

All the three approaches we have discussed for dependency injection are ok if we have only one level of dependency. But what if the concrete classes are also dependent of some other abstractions. So if we have chained and nested dependencies, implementing dependency injection will become quite complicated. That is where we can use IoC containers. IoC containers will help us to map the dependencies easily when we have chained or nested dependencies.


No comments:

Post a Comment