Pages

Wednesday, March 21, 2012

Inversion of Control : A beginner Guide

What is Problem?
Let, there is a class called Kids.cs. Purpose of this class is to maintain name and age of kids of a particular person.

Kids.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IOC
{
  class Kids
  {
  private int age;
  private string name;
  public Kids(int age, string name)
  {
  this.age = age;
  this.name = name;
  }
 
  public override string ToString()
  {
  //return base.ToString();
  string m = this.age.ToString();
  return "KIDs Age " + m + " Kids Name " + name;
  }

  }
}
Now requirement is like each person has Kids. So at time of creation of a Person, associated Kids should also get created. So this may achieve by following code
Person.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IOC
{
  class Person
  {
  private int age;
  private string name;
  private Kids obj;
  public Person(int personAge,string personName, int kidsAge, string kidsName)
  {
  obj = new Kids(kidsAge, kidsName);
  age = personAge;
  name = personName;
  }
 
  public override string ToString()
  {
  //return base.ToString();
  string s= age.ToString();
  Console.Write(obj);
  return "ParentAge" + s + " ParentName" + name;
  }
  }
}
Main.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IOC
{
  class Program
  {
  static void Main(string[] args)
  {
  Person p = new Person(35, "Dev", 6, "Len");
  Console.WriteLine(p);
  Console.Read();
  }
  }
}
Output


The above code is a typical example of COMPOSITION design pattern or Object Dependency.
Note: What is Object Dependency?

When one objects needs other object for its working then it is called one object is dependent on other object.

Let there are three classes Man, Woman and Children
If Man-> Woman
And Woman -> Children
So Man -> Children
This is called Transitive Object Dependency.
Object Coupling and Object Dependency are same term.
A Good Design should contain loose object coupling or object dependency.

Problems in above approach
  1. It is using Part of Relationship. 
  2. Here object of Kids has been created inside constructor of Person class. So here coupling is very high or tight.
  3. If due to any reason object creation of Kids is failed. Then Person class also cannot be instantiated in its constructor itself. 
  4. If object of Person class is killed then by default object of Kids class is also getting killed. 
  5. If a new type of Kids has been created or a new property is being added in Kids class then it need code modification in Person class also. 
  6. This also raises chances of Dangling Reference.
  7. Person class cannot work for Default constructor. 
  8. Kidsâ?T class cannot work for Default constructor.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IOC
{
  class Person
  {
  private int age;
  private string name;
  private Kids obj;    (Refrence) 
  public Person(int personAge,string personName, int kidsAge, string kidsName)
  {
  obj = new Kids(kidsAge, kidsName);  (known Concrete class)
  age = personAge;
  name = personName;
  }
 
  public override string ToString()
  {
  //return base.ToString();
  string s= age.ToString();
  Console.Write(obj);
  return "ParentAge" + s + " ParentName" + name;
  }
  }
}

How to solve above problem?
  1. Assign task of object creation (Kids class) to some other entity, like other class, another function. 
  2. Assign task of object creation to third party.
So, assigning task of object creation to Third Party is somehow INVERTING CONTROL to third party. And this is called "INVERSION OF CONTROL"
In other words IOC could be defined as

"Delegating task of object creation to third party,  to achieve low coupling between objects and to minimize dependency between objects is called Inversion of Control design pattern ".

So IOC says,
  1. Main class (Pesron.cs) which is composing other class, should not directly depends on implementation of other class (Kids.cs) . 
  2. There should be an abstraction between classes and classes should fully depend upon that abstraction. 
  3. Abstraction could be either an interface or and abstract class.
Dependency Injection
This is the way to implement IOC.  Dependency Injection
  1. Eliminates tight coupling between objects. 
  2. Make object and application more flexible. 
  3. It facilitates creation of more loosely coupled objects and their dependencies.
"Dependency Injection isolates implementation of object from the construction of object on which it depends".



Constructor Injection

Here object reference would get pass to constructor of business class Person.  In this case, since Person class depends on Kids class.  So reference of Kids class will pass to constructor of Person class. So at the time of object creation of Person class, Kids class will get instantiated.
Steps to implement constructor Injection

Step 1:  Create an interface

IBuisnessLogic.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IOC
{
  public interface IBuisnessLogic
  {
 
  }
}
  1. Only methods of interface will be exposed to business logic class (Person)
Step 2:  Implement interface to Kids class.

Kids.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IOC
{
  public class Kids :IBuisnessLogic
  {
  private int age;
  private string name;
  public Kids(int age, string name)
  {
  this.age = age;
  this.name = name;
  }
 
  public override string ToString()
  {
 
  string m = this.age.ToString();
  return "KIDs Age " + m + " Kids Name " + name;
  }
 

  }
}

Object of Kids class is going to be referenced by Person class. So this class needs to implement interface.

Step 3: 

Make reference of interface in Person class.

Person.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IOC
{
  class Person
  {
  private int age;
  private string name;
  IBuisnessLogic refKids;
  public Person(int personAge,string personName,IBuisnessLogic obj)
  {
 
  age = personAge;
  name = personName;
  refKids = obj;
  }
 
  public override string ToString()
  {
  string s= age.ToString();
 
  return "ParentAge" + s + " ParentName" + name;
  }
  }
}

Step 4: 

Now to create a third party class, where task of, creation of object will be done.

IOCClass.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IOC
{
  class IOCClass
  {
  IBuisnessLogic objKid = null;
  Person p;
 
  public void factoryMethod()
  {
  objKid = new Kids(12,"Ren");
  p= new Person (42,"David",objKid);
  }
  public override string ToString()
  {
  //return base.ToString();
  Console.WriteLine(p);
  Console.WriteLine(objKid);
  return "Displaying using Constructor Injection";

  }
  }
}

In above code inside a factorymethod (), object is getting created.

Step 5
:

Now using third party class at client side

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IOC
{
  class Program
  {
  static void Main(string[] args)
  {
 
  IOCClass obj = new IOCClass();
  obj.factoryMethod();
  Console.WriteLine(obj);


  Console.Read();
  }
  }
}

Disadvantage

  1. In constructor Injection, business logic class cannot have default constructor.
  2. Once the class is instantiated, objectâ?Ts dependency cannot be changed then.
Setter Injection
This uses the Properties to inject the dependency.  Here rather than creating reference and assigning them in constructor, it has been done in Properties.  By this way, Person class could have default constructor also.

Advantage:
  1. It is more flexible than constructor injection. 
  2. Here dependency of object can be changed without creating any instance. 
  3. Here dependency of objet can be changed without changing the constructors. 
  4. Setters has constructive and self descriptive meaningful name that simplify understanding and usning them .
Implementation:

Step 1
:
same as Constructor Injection.

Step 2: Same as Constructor Injection.

Step 3:  Pesron.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IOC
{
  class Person
  {
  private int age;
  private string name;
  //private Kids obj;
  private IBuisnessLogic refKids;
  public Person(int personAge,string personName)
  {
 
  age = personAge;
  name = personName;
 
  }
  public IBuisnessLogic REFKIDS
  {
  set
  {
  refKids = value;

  }
  get
  {
  return refKids;
  }
  }
 
  public override string ToString()
  {
 
  string s= age.ToString();
 
  return "ParentAge" + s + " ParentName" + name;
  }
  }
}

In Person class, there is Property REFKIDS, which is setting and getting value of reference of interface.

Step 4:
There are some changes in third party class.

IOC.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IOC
{
  class IOCClass
  {
  IBuisnessLogic objKid = null;
  Person p;
 
  public void factoryMethod()
  {
  objKid = new Kids(12,"Ren");
  p= new Person (42,"David");
  p.REFKIDS = objKid;
  }
  public override string ToString()
  {
  //return base.ToString();
  Console.WriteLine(p);
  Console.WriteLine(objKid);
  return "Displaying using Setter Injection";

  }
  }
}

Step 5:
Same as constructor injection.

This interface would be implemented by Business Logic class.  Here Kids is a business logic class. 

No comments: