Dependency Injection
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
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(); } }
DatabaseFactoryfactory= new DatabaseFactory(); IPersonDatabase personDatabase = factory.CreateDatabase(DatabaseType.Microsoft); DataReader dataReader = new DataReader(personDatabase );
Dependency Injection
Containers
Benefits
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.