The Inversion of Control Pattern (IoC)

Hi there! It’s me, remember me?

It’s been a while, a lot of things have happened; good things, no worry about that… I just forgot about this blog and recently I read some good stuff about something that I could use to make a good article… so here we are!

Today I’ll talk about a pattern I’ve been using for more than one year and a half and it’s a proven usefulness: The inversion of control pattern (IoC).

Definition

When a class (say ClassA) depends on other class (say ClassB) and it needs some instance of it in order to do its job, we say that ClassA is coupled with ClassB. If ClassA needs to know a lot of details of ClassB then we say it’s tightly coupled.

public class ClassB
{
    public void SomethingCool() { ... }
}

public class ClassA
{
    private ClassB svc;
    public ClassA()
    {
        svc = new ClassB();
    }

    public void DoSomethingInteresting()
    {
        svc.SomethingCool();
    }
}

Coupling is a problem for two reasons, mainly:

  • Changes in ClassB have the risk of breaking ClassA.
  • Designs are not flexible and it’s difficult to modify ClassA so that it uses the services provided by ClassB differently.

Normally, the best way to reduce coupling consists of introducing some abstraction layer between both, implemented by some abstract class or interface, so that ClassA depends on ClassB in those abstraction terms.

public interface ICoolService
{
    void SomethingCool();
}

public class ClassB : ICoolService
{
    public void SomethingCool() { ... }
}

public class ClassA
{
    private ICoolService svc;

    public ClassA()
    {
        svc = new ClassB();
    }

    public void DoSomethingInteresting()
    {
        svc.SomethingCool();
    }
}

This solves almost everything, because ClassA still needs to determine what implementation of the abstraction will it use.

Moving out of the dependant class (ClassA) the creation of the dependency (ClassB) is what the IoC (Inversion of Control) Pattern tries to solve. The name reflects what it does: invert the control bewteen the “dependee” and the so called “depender” (ClassA -> ClassB).

IoC is an abstract pattern that doesn’t explain how to achieve our purpose. Two common ways to implement it are:

  • Service Locator
  • Dependency Injection

The Service Locator Pattern (SL)

The aim of this pattern is to achieve IoC making the software components get their dependencies from an external component called Service Locator (SL).

There are two kinds of SL:

Strongly typed

public interface IServiceLocator
{
    ICoolService GetServiceB();
}

and then:

public class ClassA
{
    private ICoolService svc;

    public ClassA(IServiceLocator sl)
    {
        svc = sl.GetServiceB();
    }

    public void DoSomethingInteresting()
    {
        svc.SomethingCool();
    }
}

The code who instantiates ClassA needs to provide an instance of a service that implements IServiceLocator. This interface returns elements of services interfaces: IService1, IService2,… to that all client classes (such as ClassA) are loosely coupled to the services. As you can see, we delegated the problem of instancing some precise ClassB on the SL.

The problem of this approach is that the IServiceLocator is not flexible regarding the services it provides. Adding new services after it was defined may require to modify some existing classes in order to use those services.

Weakly typed

public interface IServiceLocator
{
    TService GetServiceB<TService();
}

so:

public class ClassA
{
    private ICoolService svc;

    public ClassA(IServiceLocator sl)
    {
        svc = sl.GetServiceB<ICoolService>();
    }

    public void DoSomethingInteresting()
    {
        svc.SomethingCool();
    }
}

Thus, the SL can provide new services without knowing about them ahead of time, reducing maintenance.

On the other hand, the weakly-typed SL can do little custom configuration for each service provided, since it is so generic.

The Dependency Injection Pattern (DI)

Instead of having an intermediary object that handles all the dependencies, these are directly received during instanciation as constructor parameters. This kind of DI is called Constructor Injection.

public class ClassA
{
    private ICoolService svc;

    public ClassA(ICoolService someSvc)
    {
       svc = someSvc;
    }

This way dependencies are explicit int he constructor and, by reading the it, we can figure out what dependencies have the whole ClassA.

Contrariwise, when using the SL we need to read the whole ClassA looking for the SL uses to get a picture of the dependencies ClassA has.

An alternative to the Constructor Injection is the Property Injection, which consists of defining in the client class (ClassA) a property of the interface implemented by the service it depends on and rely on someone filling it.

public class ClassA
{
    private ICoolService svc;

    public ICoolService CoolService
    {
        get { return svc; }
        set { svc = value; }
    }
}

The constructor is cleaner -or even redundant- since it doesn’t require all the services stuff.

The problem with this implementation is that we trust that someone will provide the property instanciated, otherwise a null exception will be raised… unless we protect every single access to the service checking for null, which could hide bugs in the code.

That’s why Constructor Injection is strongly recommended.

Dependency Injection Containers

There’s some unanswered question still:

how we provide the implementations of the dependencies in the first place?

So far we’ve moved the dependencies out of the business code but that’s just… moving the problem to a different place instead of solving it. If the whole system bases on DI then someone will provide implementations for… everyone else.

Here’s where Dependency Injection Containers come in place. DI Containers are libraries that implement what we need. They provide an API to define who implements what, so that when someone needs the what, some who is provided by the container. It’s like a SL extracted in an external library.

Testing

Testing gets huge benefits of using IoC, since we can mock dependencies and inject them in the code by just setting up a little bit the DI Container to tell it that, when testing, the implementations are provided by the mocks and not the actual implementations. Therefore, with no fluff in code we can easily test it.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s