Sunday, August 17, 2008

Dependency Injection and Inversion of Control Explained

Dependency injection (also called inversion of control) is an interesting design pattern that I am now utilizing in the code I write.  The purpose of this pattern is to achieve a loose-coupling across relationships within classes, which also leads to much cleaner code and eases the ability to write unit tests.  The name may sound rather intimidating but the concept is fairly simple. Say you have a class 'walrus' that needs a 'walrusService'  instance in order to do its work.  Traditionally, I would code up the class like this:

public class Walrus
{
private readonly WalrusService walrusService =
new WalrusService();

public void DoSomeWork()
{
walrusService.DoSomeWork();
}

public void DoLotsOfWork()
{
walrusService.DoLotsOfWork();
}

public int SomeIntProperty
{
get;
set;
}
}


public class WalrusService
{
public void DoSomeWork()
{
Console.WriteLine("Doing some work...");
}

public void DoLotsOfWork()
{
Console.WriteLine("Doing lots of work...");
}
}

Notice how the Walrus class above manages its dependency on the WalrusService  to do some work. The class is tightly-coupled to the service class and there is no easy way to swap the service out for a different one.  The Walrus class also needs to know how to create an instance of the Walrus service internally.


Using dependency injection combined with interface-based programming methodologies will allow us to loosely-couple this dependency and will make the Walrus class no longer care about managing the dependency on the Walrus service.


The first thing I am going to do is make the WalrusService implement an interface. ReSharper is awesome for this, just right click on the Walrus class, go to the Refactor section and click Extract interface...


public interface IWalrusService
{
void DoSomeWork();
void DoLotsOfWork();
}
public class WalrusService : IWalrusService
{
public void DoSomeWork()
{
Console.WriteLine("Doing some work...");
}
public void DoLotsOfWork()
{
Console.WriteLine("Doing lots of work...");
}
}

Now I will create a constructor on the Walrus class that takes an instance of the IWalrusService class. This is where the injection/inversion concepts are taking place. Here is the new Walrus class:

public class Walrus
{
private readonly IWalrusService walrusService;

public Walrus(IWalrusService walrusService)
{
this.walrusService = walrusService;
}

public void DoSomeWork()
{
walrusService.DoSomeWork();
}

public void DoLotsOfWork()
{
walrusService.DoLotsOfWork();
}

public int SomeIntProperty
{
get;
set;
}
}

Performing this small change allows the Walrus class to no longer care about what service is being handed to it... as long as it is an IWalrusService then life is good. This is a good way to refactor code that is calling a service that hits the database because now that service can be mocked in a unit test scenario. If all classes are written to take its dependencies in the constructor, then relationships are always very clear and become easier to manage. I will write about Inversion of Control containers soon. These containers (such as the Castle Windsor IoC container) make these relationships even easier to manage from the caller's standpoint.

No comments: