| It has been suggested that Dependency inversion principle be merged into this article or section. (Discuss) |
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 more clearly describe the mechanism.[1]
Contents |
Basics
Conventionally, if an object, in order to accomplish a certain task, needs a particular service, it will also be responsible for instantiating and disposing of (removing from memory, closing streams, etc.) the service, therefore making it more complex and hard to maintain. Ideally, this object would not need to manage its services life cycle but just have a reference to an implementation of the said services and invoke its relevant behaviors. Dependency injection is a design pattern that can be applied to provide an object with its dependencies and move the code related to the service life cycle to a more appropriate place.
Such pattern involves at least three elements: a dependent, its dependencies and a provider. The dependent is an object that is expected to accomplish a relevant task in a computer program. In order to do so, it needs the help of other objects (the dependencies) that provide specialized services. The provider is the component that is able to compose the dependent and its dependencies so they are ready to be used, while also managing other aspects of these objects life cycle, such as when and how they are instantiated (cached or not, for example). This provider may be implemented, for example, as a service locator, an abstract factory, a factory method or a more complex structure, like a framework.
As a simple example of the above explanation, we can think of a car as the dependent, the engine as the dependency and a car factory as a provider. A car does not know how to install an engine on itself, but it needs an engine to run. The assembling of an engine on a car is a car factory responsibility.
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.
Code illustration using Java
Using the car/engine example above mentioned, the following Java code shows a typical arrangement with no dependency injection applied:
public class Car { private Engine engine = new Engine(); /** @returns the car speed */ public int onAcceleratorPedalStep(int gasPedalPressure) { engine.setFuelValveIntake(gasPedalPressure); int torque = engine.getTorque(); int speed = ... //math to get the car speed from the engine torque return speed; } } //omitting the Engine class since it isn't relevant to this example //or its implementation is unknown
As shown, the Car class needs to create an instance of an Engine class to calculate its speed based on how much pressure is made on the accelerator pedal. A similar implementation would instantiate the Engine inside the onAcceleratorPedalStep method, but such an approach still forces the Car class to know how to instantiate its own Engine.
Now, should this example use dependency injection, a possible implementation would be:
public class Car { private Engine engine; public void setEngine(Engine engine) { this.engine = engine; } /** @returns the car speed */ public int onAcceleratorPedalStep(int gasPedalPressure) { engine.setFuelValveIntake(gasPedalPressure); int torque = engine.getTorque(); int speed = ... //math to get the car speed from the engine torque return speed; } } //omitting the Engine class since it isn't relevant to this example //or its implementation is unknown public class CarFactory { public Car buildCar() { Car car = new Car(); Engine engine = new Engine(); car.setEngine(engine); return car; } }
In this example, the CarFactory class represents the provider. It is a simple application of the factory method design pattern that makes it possible for the Car class to not need to know how to get an engine for itself. This is now CarFactory's responsibility.
This example does not show the full potential of dependency injection since the CarFactory is very simple. To make it a little more interesting one could consider designing it to provide a single instance of Engine to all cars it builds. More instantiation strategies could also exist and be used as specified in a CarFactory's configuration file (a typical feature in dependency injection frameworks). Also, note that in real programs there will be many classes that, like Car, will need to use many components. In this case, the provider's capability to inject dependencies will remove a lot of coding effort from the dependents.
Benefits and issues
One important benefit of using dependency injection approach is the reduction of boilerplate code in the application objects since all work to initialize or setup dependencies will be made in the provider component[2].
Also, it 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 fake 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. 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 which the framework uses to inject the dependency.
- Type 3 or constructor injection, in which the dependencies are provided through the class constructor. This is the main form used by PicoContainer, although it also supports setter injection.
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:
See also
Further reading
- A beginners guide to Dependency Injection
- What is Dependency Injection? - An alternative explanation - Jakob Jenkov
- Dependency Injection & Testable Objects: Designing loosely coupled and testable objects - Jeremy Weiskotten; Dr. Dobb's Journal, May 2006.
- Design Patterns: Dependency Injection -- MSDN Magazine, September 2005
- Writing More Testable Code with Dependency Injection -- Developer.com, October 2006
- Domain Specific Modeling (DSM) in IOC frameworks
- The Rich Engineering Heritage Behind Dependency Injection - Andrew McVeigh - A detailed history of dependency injection.
- P of EAA: Plugin
References
| This article includes a list of references, related reading or external links, but its sources remain unclear because it lacks inline citations. Please improve this article by introducing more precise citations where appropriate. (October 2007) |
This entry is from Wikipedia, the leading user-contributed encyclopedia. It may not have been reviewed by professional editors (see full disclaimer)


