Dependency injection

From Wikipedia, the free encyclopedia

Dependency injection (DI) in Computer programming refers to the process of supplying an external dependency to a software component. It is a specific form of inversion of control where the concern being inverted is the process of obtaining the needed dependency.

Conventionally, if an object needs to gain access to a particular service, the object takes responsibility to get hold of that service: either it holds a direct reference to the location of that service, or it goes to a known 'service locator' and requests that it be passed back a reference to an implementation of a specified type of service. By contrast, using dependency injection, the object simply provides a property that can hold a reference to that type of service; and when the object is created a reference to an implementation of that type of service will automatically be injected into that property - by an external mechanism.

When the dependency injection technique is used to decouple high-level modules from low-level services, the resulting design guideline is called the Dependency inversion principle.

The dependency injection approach offers more flexibility because it becomes easier to create alternative implementations of a given service type, and then to specify which implementation is to be used via a configuration file, without any change to the objects that use the service. This is especially useful in unit testing, because it is easy to inject a mock implementation of a service into the object being tested. On the other hand, excessive use of dependency injection can make applications more complex and harder to maintain: in order to understand the application's behaviour the developer needs to look at the configuration as well as the code, and the configuration is "invisible" to IDE-supported reference analysis and refactoring unless the IDE specifically supports the dependency injection framework.

Contents

[edit] A Code Illustration using Java

Suppose that IFoo is a common class, specifying a certain interface:

public interface IFoo
{
      void bar(); // Perform bar
      void baz(); // perform baz
}

There exist also a number of implementation classes, each of them implementing IFoo in some way:

public class DatabaseFoo
      implements IFoo
{
      void bar()
      {
          db.select_bar().execute(); // Use the database to do bar
      }
 
      void baz()
      {
          db.select_baz().run(); // Use the database to do baz
      }
}
public class PixieDustFoo
      implements IFoo
{
      void bar()
      {
          cast_spell("bar"); // Magic!
      }
 
      void baz()
      {
          cast_spell("baz"); // Magic!
      }
}
public class EnterpriseFoo
      implements IFoo
{
      void bar()
      {
            EnterpriseFactoryObserverFactoryCreator efofc("bar");
            efofc.creatify();
            efofc.preparify();
            efofc.configurise();
            efofc.make_award_winning();
            efofc.opportunities.leverage();
      }
 
      void baz()
      {
            EnterpriseFactoryObserverFactoryCreator efofc("baz");
            efofc.creatify();
            efofc.preparify();
            efofc.configurise();
            efofc.make_award_winning();
            efofc.opportunities.leverage();
      }
}

IFoo only specifies the operations available in its interface, but doesn't itself provide any implementation, instead leaving that to other implementer classes. This way a user wishing to use the IFoo functionality can use any implementation, not knowing anything more about them than that they conform to the Foo interface.

An object needing the services defined by IFoo needs to get an instance of a class that implements IFoo:

public class ImportantClass {
      IFoo foo;
 
      public ImportantClass()
      {
            this.foo = new EnterpriseFoo();
      }
 
      void do_really_important_stuff()
      {
            this.foo.bar();
      }
}

However, this defeats the entire point of using an interface instead of a concrete implementation. To fix that, it's enough to let the outside caller provide the desired implementation:

public ImportantClass(IFoo foo)
{
    this.foo = foo;
}

When using dependency injection there is usually a configuration mechanism or architecture for deciding which implementation gets injected into an object.

[edit] Existing frameworks

Dependency injection frameworks exist for a number of platforms and languages including:

ActionScript

C++

ColdFusion

Java

.NET

PHP4

PHP5

Perl

Python

Ruby

[edit] See also

[edit] External links