Thursday, April 4, 2013

Inversion of Control (IoC) Pattern

I have been involved in many architectural discussion lately, where groups of people have been throwing around ideas on the correct way to build systems.  I am always coming from a position of loosely coupling and making sure that all aspects of your system are interchangeable and have the ability to be dynamically changed or replaced without system wide impact.  One topic that I find myself mentioning over and over again is the pattern known as Inversion of Control. Inversion of control (IoC) is a OOP technique by which  object coupling is bound at run time by an another object that is typically not known at compile time using static analysis.  The basic idea of this pattern is separate the creation of an object from the class which is trying to consume it.

The problem

As with every design pattern, the reasoning behind IoC is to avoid the possibility of design related problems.  For example, let's create an Appointment class which contains a Person class object. The biggest issue with the code below is tight the coupling between classes. In other words the Appointment class depends on the Person object. This main seem innocuous enough at a glance.  But, the byproduct of this design is that  if for any reason Person class changes, it will lead to a compile of the Appointment class. Then, in our world any object compilation leads to regression testing of the recompiled object, even though there was not an actual change. 
public class Person
{
}

public class Appointment
{
    private Person person;

    public Appointment()
    {
        person = new Person();
    }
}
The biggest problem with the sample code is that the appointment class controls the creation of Person object.  The patient class is directly referenced in the Appointment class which leads to tight coupling between these two objects.The Appointment class is aware of the Person class type. So if we add new Person types (like patient, sales person, employee, or pet), it will lead to changes in the Appointment class also as Appointment class is exposed to the actual Person implementation.  This also means that the creation of the Appointment class is dependent upon the successful creation of the Patient object within it's constructor.

The solution

If we are able to shift this task / control of object creation from the Appointment class to some other entity we have solved our problem. This means we are able to invert the control to a third party object and thus have found the solution. Some people call the IoC pattern the 'Hollywood' pattern because the simplest explanation of it's purpose is summed up the in phrase "Don't call us, we'll call you." This is a good summary of the idea of this pattern. There are many ways to accommodate this pattern with varying degrees of overhead. In my opinion, the simplest implementation of an IoC Container. IoC containers are used to simplify the provision of a dependant class's dependencies. In the most basic form, an IoC container is an implementation of the service locator design pattern that permits pre-instantiated objects to be registered with the container and later extracted. To substitute a new class and modify the operation of an entire solution, only the initial registration of the type need be changed.

IoC Container

Some IoC containers allow you to register types, rather than objects, and instantiate the type when requested, possibly using parameters. Others allow the registrations to be deserialised from an XML file, which could be modified in a text editor. In this article we will create a basic IoC container that does not include these additional features. This will demonstrate the use of IoC containers with the simplest possible code. You may decide to enhance the code to add extra features for your own use. However, you should also consider obtaining one of the many alternative IoC container solutions that are currently available. Following is the code to create a very a basic IoC container.
public static class IoC
{
    static Dictionary<Type, object> _registeredTypes = new Dictionary<Type, object>();

    public static void Register<T>(T toRegister)
    {
        _registeredTypes.Add(typeof(T), toRegister);
    }

    public static T Resolve<T>()
    {
        return (T)_registeredTypes[typeof(T)];
    }
}

Using the IoC Container

To illustrate the usage of the IoC container we first need to create an interface and a class that implements it. We will later register an instance of the class for the interface's type. The code for a simple interface and class that is used to grab a value are as follows:
public interface IPerson
{
    void SayYourName(string name);
}


public class Person : IPerson
{
    public void SayYourName(string name)
    {
        Console.WriteLine(name);
    }
}
We can now register the interface's type and provide a new Person object, which will be returned whenever the type is resolved. You would usually do this when your application is first started. In this example we will only register one type. In a real solution you can register as many types as are required for the operation of your software.
static void Main(string[] args)
{
    IoC.Register<IPerson>(new Person());
    IPerson person = IoC.Resolve<IPerson>();
    person.SayYourName("Jim Garrett");  
}
Once registered, any code that has access to the IoC class can resolve the type. In the sample the first line requests the object from the IoC container that implements IPerson. This returns the previous registered Person object. The object is then used to output a message to the console.

No comments:

Post a Comment