Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Inversion of controls for dummies

0.00/5 (No votes)
22 Feb 2013 1  
The main purpose of the article is to give some help to those who want to learn something about the inversion of control design pattern.

Introduction

The main purpose of the article is to give some help to those who want to learn something about the inversion of control design pattern.

I've decided to create the article because I've spent a lot of time trying to find something easy to read and useful on the internet about this pattern. The article is based on a simple and complete application example.

First of all you should know that the main purpose of the inversion of controls design pattern is to avoid dependencies between classes. Using inversion of controls your code gets decoupled so you can easily exchange implementations of an interface with alternative implementations.

Using the code

Bellow you can see the structure of my (dummy) project:

What is the project about?

My projects is just reading some data (a list of products) and displays the data on the console.

The data may come from the SQL database or from XML file.

So, I have the object Product that has the next properties: 

C++
public class Product
{
    public Guid ID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public double Price { get; set; }
    public double Quantity { get; set; }
}

So, the main secret of my project that implements the inversion of control pattern are the next classes: IProductDeposit interface, Container, and ProductDepositListeners class.

IProductDeposit interface has just a simple method: GetProducts().

C#
public interface IProductsDeposit
{
     List<Product> GetProducts();
}

Than, I have ProductDepositDB and ProductDepositXML classes which are both implementing the IProductDeposit interface. ProductDepositDB class is used to get my list of products from my SQL database and ProductDepositXML is used to get my data from an XML file (bellow you can see a snippet of code from my XML file)

XML
<?xml version ="1.0" encoding="utf-8" ?>
<products>
   <product>
      <id>9a8f19e0-1abe-401b-a28f-ae0978538cd1</id>
      <name>Milli</name>
      <description>Milk</description>
      <price>2</price>
      <quantity>50</quantity>
   </product>
  <product>
    <id>9a8f19e0-1abe-401b-a28f-ae0978538cd2</id>
    <name>Fulga</name>
    <description>Milk</description>
    <price>3</price>
    <quantity>60</quantity>
   </product>
</products>

ProductDepositListeners is the class where the magic happens. This is where the injection of control take place. The class has an IProductsDeposit private field which is responsible for the injection process.

C#
namespace InversionOfControlsDummyApp.AppModels
{
  public class ProductsDepositListener
  {
    private IProductsDeposit _productsDeposit;

    public ProductsDepositListener(IProductsDeposit productsDeposit)
    {
      _productsDeposit = productsDeposit;
    }


    public List<Product> GetProducts()
    {
      return _productsDeposit.GetProducts();   
    }
  }
}

Now, it's very easy to choose how do I want to get my products (from my XML file or from my database) without changing anything in the source code. The Container class makes the decision.

C#
public class Container
{
    public delegate object ChooseDatasource();

    private readonly Dictionary<Type, ChooseDatasource> _datasources = new Dictionary<Type, ChooseDatasource>();


    public void AddComponent<T>(ChooseDatasource ds)
    {
      _datasources.Add(typeof(T), ds);
    }


    public T Create<T>()
    {
      return (T)_datasources[typeof(T)]();
    }
}

In my Main class I just need to create an instance of the Container object where I will add a component of ProductsDepositListener class and a component from which I want to get my data (ProductDepositDB or ProductDepositXML).

This is the the Main class when I want to get my list of products from my database:

C#
static void Main(string[] args)
{
      Container container = new Container();

      container.AddComponent<ProductsDepositListener>(() =>
      {
        IProductsDeposit fileReader = container.Create<IProductsDeposit>();
        return new ProductsDepositListener(fileReader);

      });

      container.AddComponent<IProductsDeposit>(() =>
        {
          IProductsDeposit pdDB = new ProductsDepositDB();
          return pdDB;
        });

      ProductsDepositListener productDepositListener = container.Create<ProductsDepositListener>();
      var result = productDepositListener.GetProducts();

      DisplayProducts(result);

This is the the Main class when I want to get my list of products from my XML file: 

C#
static void Main(string[] args)
{
      Container container = new Container();

      container.AddComponent<ProductsDepositListener>(() =>
      {
        IProductsDeposit fileReader = container.Create<IProductsDeposit>();
        return new ProductsDepositListener(fileReader);

      });

      container.AddComponent<IProductsDeposit>(() =>
      {
        IProductsDeposit pdXML = new ProductDepositXML();
        return pdXML;
      });

      ProductsDepositListener productDepositListener = container.Create<ProductsDepositListener>();
      var result = productDepositListener.GetProducts();

      DisplayProducts(result);

I hope that this article will be a good starting point for those who want to implement the inversion of control pattern in their applications. I have also added a zip with my application for those who needs it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here