Share on Facebook Share on Twitter Email
Answers.com

Dependency injection

 
Wikipedia: Dependency injection

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. The term was first coined by Martin Fowler to describe the mechanism more clearly.[1]

Contents

Basics

Without the concept of dependency injection, a consumer who needs a particular service in order to accomplish a certain task would be responsible for handling the life-cycle (instantiating, opening and closing streams, disposing, etc.) of that service. Using the concept of dependency injection, however, the life-cycle of a service is handled by a dependency provider (typically a container) rather than the consumer. The consumer would thus only need a reference to an implementation of the service that it needed in order to accomplish the necessary task.

Such a pattern involves at least three elements: a dependent, its dependencies and an injector (sometimes referred to as a provider or container). The dependent is a consumer that needs to accomplish a task in a computer program. In order to do so, it needs the help of various services (the dependencies) that execute certain sub-tasks. The provider is the component that is able to compose the dependent and its dependencies so that they are ready to be used, while also managing these objects' life-cycles. This provider may be implemented, for example, as a service locator, an abstract factory, a factory method or a more complex abstraction such as a framework.

The following is an example. A car (the consumer) depends upon an engine (the dependency) in order to move. The car's engine is made by an automaker (the dependency provider). The car does not know how to install an engine into itself, but it needs an engine in order to move. The automaker installs an engine into the car and the car utilizes the engine to move.

When the concept of dependency injection is used, it decouples high-level modules from low-level services. The result is called the dependency inversion principle.

Code illustration using Java

Using the car/engine example above mentioned, the following Java examples show how coupled dependencies (manually-injected dependencies) and framework-injected dependencies are typically staged.

public interface Engine
{
    public float getEngineRPM();
 
    public void setFuelConsumptionRate(float flowInGallonsPerMinute);
}
 
public interface Car
{
    public float getSpeedInMPH();
 
    public void setPedalPressure(float pedalPressureInPounds);
}

Highly coupled dependency

The following shows a common arrangement with no dependency injection applied:

public class DefaultEngineImpl implements Engine
{
    private float engineRPM = 0;
 
    public float getEngineRPM()
    {
        return engineRPM;
    }
 
    public void setFuelConsumptionRate(float flowInGallonsPerMinute)
    {
        engineRPM = ...;
    }
}
 
public class DefaultCarImpl implements Car
{
    private Engine engine = new DefaultEngineImpl();
 
    public float getSpeedInMPH()
    {
        return engine.getEngineRPM() * ...;
    }
 
    public void setPedalPressure(float pedalPressureInPounds)
    {
        engine.setFuelConsumptionRate(...);
    }
}
 
public class MyApplication
{
    public static void main(String[] args)
    {
        Car car = new DefaultCarImpl();
        car.setPedalPressure(5);
        float speed = car.getSpeedInMPH();
    }
}

In the above example, the Car class creates an instance of an Engine implementation in order to perform operations on the car. Hence, it is considered highly coupled because it couples a car directly with a particular engine implementation.

In cases where the DefaultEngineImpl dependency is managed outside of the scope of the Car class, the Car class must not instantiate the DefaultEngineImpl dependency. Instead, that dependency is injected externally.

Manually-injected dependency

Refactoring the above example to use manual injection:

public class DefaultCarImpl implements Car
{
    private Engine engine;
 
    public DefaultCarImpl(Engine engineImpl)
    {
        engine = engineImpl;
    }
 
    public float getSpeedInMPH()
    {
        return engine.getEngineRPM() * ...;
    }
 
    public void setPedalPressure(float pedalPressureInPounds)
    {
        engine.setFuelConsumptionRate(...);
    }
}
 
public class CarFactory
{
    public static Car buildCar()
    {
        return new DefaultCarImpl(new DefaultEngineImpl());
    }
}
 
public class MyApplication
{
    public static void main(String[] args)
    {
        Car car = CarFactory.buildCar();
        car.setPedalPressure(5);
        float speed = car.getSpeedInMPH();
    }
}

In the example above, the CarFactory class assembles a car and an engine together by injecting a particular engine implementation into a car. This moves the dependency management from the Car class into the CarFactory class. However, this still may not be enough abstraction for some applications.

Framework-managed dependency injection

There are several frameworks available that automate dependency management by delegating the management of dependencies. Typically, this is accomplished by a Container using XML or "meta data" definitions. Refactoring the above example to use an external XML-definition framework:

    <service-point id="CarBuilderService">
        <invoke-factory>
            <construct class="Car">
                <service>DefaultCarImpl</service>
                <service>DefaultEngineImpl</service>
            </construct>
        </invoke-factory>
    </service-point>
/** Implementation not shown **/
 
public class MyApplication
{
    public static void main(String[] args)
    {
        Service service = (Service)DependencyManager.get("CarBuilderService");
        Car car = (Car)service.getService(Car.class);
        car.setPedalPressure(5);
        float speed = car.getSpeedInMPH();
    }
}

In the above example, a dependency injection service is used to retrieve a CarBuilderService service. When a Car is requested, the service returns an appropriate implementation for both the car and its engine.

As there are many ways to implement dependency injection, only a small subset of examples is shown herein. Dependencies can be registered, bound, located, externally injected, etc., by many different means. Hence, moving dependency management from one module to another can be accomplished in a plethora of ways. However, there should exist a definite reason for moving a dependency away from the object that needs it because doing so can complicate code hierarchy to such an extent that its usage appears to be "magical". For example, suppose a Web container is initialized with an association between two dependencies and that a user who wants to use one of those dependencies is unaware of the association. The user would thus not be able to detect any linkage between those dependencies and hence might cause drastic problems by using one of those dependencies.

Benefits and Drawbacks

One benefit of using the dependency injection approach is the reduction of boilerplate code in the application objects since all work to initialize or setup dependencies is handled by a provider component[2].

Another benefit is that it offers configuration flexibility because alternative implementations of a given service can be used without recompiling code. This is useful in unit testing because it is easy to inject a fake implementation of a service into the object being tested by changing the configuration file.

One drawback is that excessive or inappropriate use of dependency injection can make applications more complicated, harder to understand and more difficult to modify. Code that uses dependency injection can seem magical to some developers, since instantiation and initialization of objects is handled completely separately from the code that uses it. This separation can also result in problems that are hard to diagnose. Additionally, some dependency injection frameworks maintain verbose configuration files, requiring that a developer understand the configuration as well as the code in order to change it.

Another drawback is that some IDEs might not be able to accurately analyze or refactor code when configuration is "invisible" to it. Some IDEs mitigate this problem by providing explicit support for various frameworks. Additionally, some frameworks provide configuration using the programming language itself, allowing refactoring directly. Other frameworks, such as the Grok web framework, introspect the code and use convention over configuration as an alternative form of deducing configuration information. For example, if a Model and View class were in the same module, then an instance of the View will be created with the appropriate Model instance passed into the constructor.

Types

Fowler identifies three ways in which an object can get a reference to an external module, according to the pattern used to provide the dependency:[3]

  • Type 1 or interface injection, in which the exported module provides an interface that its users must implement in order to get the dependencies at runtime.
  • Type 2 or setter injection, in which the dependent module exposes a setter method that the framework uses to inject the dependency.
  • Type 3 or constructor injection, in which the dependencies are provided through the class constructor.

It is possible for other frameworks to have other types of injection, beyond those presented above.[4]

Existing frameworks

Dependency injection frameworks exist for a number of platforms and languages, as can be seen in the following table:

Language/platform DI Framework
Actionscript Robot Legs
ActionScript Spring ActionScript
ActionScript di-as3
ActionScript Syringe
ActionScript lowRa (AS3)
ActionScript Pixlib (AS2)
ActionScript VEGAS and AndromedA this IOC extension.(AS3/AS2/SSAS) (see Introduction IOC based ECMAScript notation)
ActionScript Parsley (AS3) as part of the Spicefactory
C++ Autumn Framework
C++ PocoCapsule/C++ IOC and DSM Framework
C++ QtIOCContainer
C++ C++ Builder coupling dependency injection and component based assembly
ColdFusion ColdSpring Framework
Delphi Delphi Pascal coupling dependency injection and component based assembly
Delphi Win32 Emballo, DI framework for Delphi Win 32
Flex Spring ActionScript
Flex Flicc
Flex Mate
Flex Swiz
Java Butterfly Container
Java Essence Java Configuration File
Java Apache Felix iPOJO
Java Google Guice
Java HiveMind
Java Plexus
Java JBoss Microcontainer
Java PicoContainer
Java Openxava
Java JBuilder coupling dependency injection and component based assembly
Java simject
Java Seasar
Java Spring Framework
Java J2EE 5 / EJB 3
Java Naked Objects
Java miocc - Microscopic Inversion of Control Container
Java Spring ME
Java Yan
Java JSR-330 Dependency Injection for Java
Java Tapestry IoC
Java 2 Micro Edition Israfil micro container (CLDC 1.1)
Java 2 Micro Edition Spring ME
JavaScript Squirrel IoC
JavaScript ContainerJS
Microsoft .NET Managed Extensibility Framework
Microsoft .NET Autofac
Microsoft .NET Castle MicroKernel/Windsor
Microsoft .NET ObjectBuilder
Microsoft .NET PicoContainer.NET
Microsoft .NET Puzzle.NFactory
Microsoft .NET Spring.NET
Microsoft .NET StructureMap
Microsoft .NET Ninject
Microsoft .NET Unity
Microsoft .NET The LinFu Framework
Microsoft .NET NauckIT.MicroKernel
Microsoft .NET WINTER4NET
PHP 4 drip
PHP 5 FLOW3
PHP 5 Crafty
PHP 5 Stubbles
PHP 5 Twittee
PHP 5 Sphicy
PHP 5 Phemto
PHP 5 DiContainer
PHP 5 Garden
PHP 5 Xyster Framework
PHP 5 Lion Framework
PHP 5 Spiral Di Container
PHP 5 Symfony Dependency Injection Container
PHP 5 Yadif
Perl The IOC Module
Perl Bread::Board
Python Zope Component Architecture
Python Spring Python
Python PyContainer
Ruby Copland
Ruby Needle

See also

Further reading

References


Search unanswered questions...
Enter a question here...
Search: All sources Community Q&A Reference topics
 
 

 

Copyrights:

Wikipedia. This article is licensed under the Creative Commons Attribution/Share-Alike License. It uses material from the Wikipedia article "Dependency injection" Read more