The purpose of IOC is to build loosely
coupled software architecture.
To understand the need of loosely
coupled architecture, let me explain the problem with tight coupling.
Consider following example:
Consider following class of Employee
public class Employee
{
int empNo;
string empName;
Address empAddress;
public Employee()
{
empAddress = new Address();
}
}
The problem here is that Employee
and Address classes are tightly coupled with each other.
Any change in Address class will
affect Employee class implementation and will require change in Employee class.
Employee class is aware of the address
class. So if we add new address types like home address, office address etc it will
require change in customer class.
Here we say class Employee has
dependency on class Address.
This situation has the following problems:
- To replace or update the dependencies, we need to change our class’s
source code.
- The concrete implementations of the dependencies have to be
available at compile time.
- Our classes are difficult to test in isolation because they
have direct references to dependencies
- Our classes contain repetitive code for creating, locating,
and managing their dependencies.
Solution to this problem is to decouple the classes and Delegate
the task of managing the dependencies to external component.
In other words we have to invert the control of creating
dependencies to a third party.
Any of the following conditions justifies using the solution
described in this pattern:
- You want to decouple your classes from their dependencies so
that the dependencies can be replaced or updated with minimal or no
changes to your classes' source code.
- You want to write classes that depend on classes whose
concrete implementations are not known at compile time.
- You want to test your classes in isolation, without using the
dependencies.
- You want to decouple your classes from being responsible for
locating and managing the lifetime of dependencies.
IOC can be implemented in several
ways. The Dependency Injection pattern and the Service Locator pattern are
specialized versions of this pattern.
Dependency Injection using Windsor container
Here I am explaining Dependency
Injection using Windsor container.
Typically, you express dependencies on
interfaces instead of concrete classes. This enables easy replacement of the
dependency concrete implementation without modifying your classes' source code.
To create loose coupling we will
Create a interface IAddress and create a concreate class Address from this
interface.
We will pass the object of IAdress to
Employee class constructor and hence if we have to add a new class as
HomeAddress we will create a new class HomeAddress implementing IAdress
interface and there will be no need to change the code in Employee class.
public class Employee
{
int empNo;
string empName;
IAddress empAddress;
public Employee(IAddress address)
{
this.empAddress = address;
}
}
public interface IAddress
{
}
public class Address : IAddress
{
public string address;
public string city;
public string state;
public Address()
{
this.address = "Default
Address";
this.city = "Default
City";
this.state = "Default
State";
}
}
Now here in this example class
Employee have dependency on class Address and if we were to create object of
class Employee without using Dependency Injection we will have to manually
create objects of all dependencies (in this case Address class object) and pass
it to Employee class creation as follows:
/*
Manually Creating Dependency object i.e.Address and passing it while creating
Employee object */
Address address = new Address() { address = "M.G.Road", city = "Shirur", state = "Maharashtra" };
Employee
emp = new Employee(address);
Using Dependency Injection
Here I am using Castle Windsor as Dependency
Injection container and there are many DI containers available which you can
use.
On application startup we will create
object of Castle Windsor and will register all components in this container.
/*
Using Dependency Injection using Castle Windsor */
WindsorContainer _windsorContainer = new WindsorContainer();
//
Register All types manually
_windsorContainer.Register(Component.For<IAddress>().ImplementedBy<Address>());
_windsorContainer.Register(Component.For<Employee>());
We can manually register all types in
WindsorContainer as shown above or we can register all types in the assembly as
shown below.
//
Register All types in current assembly
_windsorContainer.Register(Castle.MicroKernel.Registration.AllTypes.FromThisAssembly().Pick()
.WithService.DefaultInterfaces().AllowMultipleMatches());
To create object of Employee using DI you
do not need to create object of Address class. DI will automatically inject
address object in Employee object.
Create Employee object as shown below
var objEmployee =
_windsorContainer.Resolve<Employee>();
This is all about the concept of IOC.
You can download code here.
Do spend your time to provide comments and feedback over here or on my mail id narenkedari@gmail.com