Pages

Monday, November 29, 2010

Dependency Injection [DI]

Also knows as Inversion of Control, facilitates the design and implementation of loosely coupled, reusable, and testable objects in your software designs by removing dependencies that often inhibit reuse. Dependency injection can help you design your applications so that the architecture links the components rather than the components linking themselves.


Object Dependency : While a class is created by using composition design pattern then it implies tightly coupled class. i.e. If Class A have instance object of Class B in it then it implies that A is dependent on class B also case B futher uses Instance of class C as public/private property/field then it creates a dependency hierarchy which implies A is also depends on Class C.


Advantages of DI
    * Loose coupling
    * Centralized configuration
    * Easily testable

Code becomes more testable because it abstracts and isolates class dependencies.

Disadvantages of DI
primarily is that wiring instances together can become a nightmare if there are too many instances and many dependencies that need to be addressed.

Types of Dependency Injection
There are three common forms of dependency injection:

   1. Constructor Injection
   2. Setter Injection
   3. Interface-based injection

Constructor Injection

Consider a scenario of two layers say MyFacade  and MyBusinessLogic layers with MyFacade  layer to operate properly depends on the MyBusinessLogic layer. All the business logic classes implement an IMyBusinessLogic interface.

So MyFacade   class uses its argument or parameterized constructor and pass the required BusinessLogic type to inject the dependency.

   interface IMyBusinessLogic
   {
     //-------------
     //-------------
     //-------------
     //-------------

   }
 
   class Prod : IMyBusinessLogic
   {
     //-------------
     //-------------
     //-------------
     //-------------
   }
 
   class Cust : IMyBusinessLogic
   {
     //-------------
     //-------------
     //-------------
     //-------------
   }
------------------------------------------------------------------------
   public class MyFacade
   {
      private IMyBusinessLogic bl;
      public MyFacade  (IMyBusinessLogic bl)
      {
         this.bl = bl;
      }
   }


So in the caller class

    IBusinessLogic p1 = new Prod();
    MyFacade   MyFacade  = new MyFacade  (p1);



Here we can see that we can pass instance of any of concrete class to the MyFacade   constructor. The constructor does not accept a concrete object; instead, it accepts any class that implements the IBusinessLogic interface.

Advantage: It is flexible and promotes loose coupling

Disadvantage:
1. Once the class is instantiated, you can no longer change the object's dependency.
2. Because you can't inherit constructors, any derived classes call a base class constructor to apply the dependencies properly. Fortunately, you can overcome this drawback using the setter injection technique.



Setter Injection:
lets you create and use resources as late as possible

This is more flexible than constructor injection because you can use it to change the dependency of one object on another without having to create a new instance of the class or making any changes to its constructor.

interface IMyBusinessLogic
   {
     //-------------
     //-------------
     //-------------
     //-------------

   }
 
   class Prod : IMyBusinessLogic
   {
     //-------------
     //-------------
     //-------------
     //-------------
   }
 
   class Cust : IMyBusinessLogic
   {
     //-------------
     //-------------
     //-------------
     //-------------
   }
------------------------------------------------------------------------
public class MyFacade
     {
      private IMyBusinessLogic bl;
 
      public IMyBusinessLogic BL
         {
          get
          {
            return bl;
          }
 
            set
          {
            bl = value;
          }
        }
     }


Usage:

   IMyBusinessLogic p1 = new Prod();
   MyFacade   bf = new MyFacade  ();
   bf.BL = p1;


Advantage:
The dependency between the MyFacade   and the instance of IMyBusinessLogic can be changed even after instantiating the MyFacade   class.

Disadvantage:
1. Setters cannot be immutable
2. It can be difficult to identify which dependencies are needed, and when.

So normally we choose constructor injection over setter injection unless you need to change the dependency after instantiating an object instance, or cannot change constructors and recompile.


Interface Injection:
This injection is used while other classes need to implement the common interface to inject the dependencies. So in the following example IMyBusinessLogic interface as a base contract to inject an instance of any of the business logic classes (Prod or Cust) into the MyFacade   class.


interface IMyBusinessLogic
   {
     //-------------
     //-------------
     //-------------
     //-------------

   }
 
   class Prod : IMyBusinessLogic
   {
     //-------------
     //-------------
     //-------------
     //-------------
   }
 
   class Cust : IMyBusinessLogic
   {
     //-------------
     //-------------
     //-------------
     //-------------
   }
------------------------------------------------------------------------
   public class MyFacade
   {
      private IMyBusinessLogic bl;
      public SetBLObject(IMyBusinessLogic bl)
      {
         this.bl = bl;
      }
   }


Usage:
   IMyBusinessLogic p1 = new Prod();         
   IMyBusinessLogic p2 = new Cust();
   MyFacade   bf = new MyFacade ();
   bf.SetBLObject(p1);        //or bf.SetBLObject(p2);


DI can can be used to abstract the dependencies of an object outside of it and make such objects loosely coupled with each other.

No comments: