Dependency Injection

When designing software, it’s a good thing to have a good separation between components, where components know as less as possible from other components. Components are specialized in one task and have well-defined interfaces (this also avoids “god classes” which knows to much or does to much) and components can be reused.

Take for example a class that is specialized in reading data from a database:
public class MicrosoftDataReader
{
     private MicrosoftSQLDatabase m_database;
     public List<Persons> GetPersons() {
          List<Persons> m_personResults;

          if(m_database.IsDatabaseOpen())
          {
               MsSqlPersons persons =  m_database.GetPersons();
              /* Convert to List<Persons> */
               m_personResults = ....
          }
          return m_personResults;
}

Another class uses this database:

class Abc()
{
 ...
 public void ReadData()
 {
   MicrosoftDataReader db = new MicrosoftDataReader();
   List<Persons> persons = db.GetPersons();
   ...
 }
 ...
}

The example above reads from a Microsoft SQL database. But what if we want to read out data from another database vendor? Since the knowledge how to read from the database is directly stored in this class, we can’t easily switch to another database or storage type. It would be easier if we introduced the interface IPersonDataReader. Classes which implement this interface, take care of retrieving person information. This interface would, for example, look like:

interface IPersonDataReader
{
  List<persons> GetPersons();
}

A class which implements this interface and writes to a MS SQL database would have a signature like this:

public class MSSqlPersonDatabase : IPersonDataReader
{
     public List<Persons> GetPersons() { /* Ms SQL specific calls */}
}

And a SQL Lite variant would look like this:

public class SqlLitePersonDatabase: IPersonDataReader
{
     public List<Persons> GetPersons() {/* SQL Lite specific calls */}
}

 

By doing this, we can easily switch in our class Abc from one type of retrieving person data to another.

Factory pattern

A common used method for creating instances of a certain type, used in the example above, is done by using the factory pattern. The factory creates an instance of a certain class, which can be for example a stubbed interface for using in unit-tests.
public class DatabaseFactory
{
   public IPersonDatabase CreateDatabase(DatabaseType databaseType)
   {
      IPersonDatabase createdDatabase= null;
      switch(databaseType())
      {
        case databaseType.Microsoft : 
               createdDatabase = new MicrosoftSQLDatabase ()
               break;
        case databaseType.SqlLite: 
               createdDatabase = new SqlLitePersonDatabase()
               break;
        case databaseType.Stub :
               createdDatabase = new PersonDatabaseStub()
               break;
      }
   }
}

public class DataReader
{
     private IPersonDatabase m_personDatabase;
 
     public DataReader(IPersonDatabase personDatabase)
     {
       m_personDatabase= personDatabase;
     }
     public List<Persons> GetPersons() {
          return personDatabase.GetPersons();
     }
}
In our class Abc we let the factory create our reader as this:
DatabaseFactoryfactory= new DatabaseFactory();
IPersonDatabase personDatabase = factory.CreateDatabase(DatabaseType.Microsoft);
DataReader dataReader = new DataReader(personDatabase );

Dependency Injection

Another way of creating objects is called “Dependency Injection” (DI). Martin Fowler is the creator of this concept, which he wrote about on his blog called “Inversion of Control Containers and Dependency Injection Pattern“.
Within DI you “inject” objects of a certain type. Normally you write a class which creates an instance of a class, along with the required parameters of the constructor. However, with DI you don’t do the creation of objects and calling of the constructor yourself. The idea behind this is to let the developer write functional code and discharge him from writing all the required infrastructure things. Also components are less hardwired to each other, which means they can be reused more efficiently.
The difference between DI and the factory pattern lies in the fact that by using the factory pattern, there is some knowledge how to create the objects within the factory class.

Containers

DI defines so-called containers. A container is responsible for maintaining the lifecycle of objects, this means creating and removing instances of objects. Within DI this is called “Inversion of Control” (or IoC). The container is filled with classes and a configuration. This configuration contains knowledge about when which type of class should be created and how the different types are linked to each other.
There are a number of frameworks, which implement the DI concepts. Most modern object oriented languages have such a framework. Examples of frameworks are AutoFac and Ninject.

Benefits

A much heard benefit is that you use DI, your code will be easier to test. I dont’ think this is a good argument to use DI. When doing TDD, you  first write your tests and your code will automatically be easy to unit test.
Another benefit is the re-usability of your code, since classes can be glued easily.

Drawbacks

The main drawback of DI is in my opinion the maintainability of your code. This seems a contradictory, since DI imposes to make re-usability of your code far more easy. However in practice I’ve seen that in bigger projects, it will get quite fast a real mess which class uses which instance. You may take shortcuts, since objects are registered at one place and can be used wherever you want. A lot of magic appears behind the scene, where you just have to know the DI framework did this magic for you. By doing the creation of objects yourself, you will have to spend some time on this, but you can easily see which instance will be created by which object. By re-reading your code or the code of someone else this is much easier to understand. Also you are more forced to think about the architecture of your program and the lifetime of your objects.

 I think for the the purpose of DI, maintainability, DI gets fast to complicated. With the use of the factorypattern your code is more easy to maintain and to read.
Posted in Uncategorized by Bruno at April 20th, 2015.

Leave a Reply