Dependency injection
In software engineering, dependency injection is a technique in which an object receives other objects that it depends on. These other objects are called dependencies. In the typical "using" relationship the receiving object is called a client and the passed (that is, "injected") object is called a service. The code that passes the service to the client can be many kinds of things and is called the injector. Instead of the client specifying which service it will use, the injector tells the client what service to use. The "injection" refers to the passing of a dependency (a service) into the object (a client) that would use it.
The service is made part of the client's state.[1] Passing the service to the client, rather than allowing a client to build or find the service, is the fundamental requirement of the pattern.
The intent behind dependency injection is to achieve separation of concerns of construction and use of objects. This can increase readability and code reuse.
Dependency injection is one form of the broader technique of inversion of control. A client who wants to call some services should not have to know how to construct those services. Instead, the client delegates the responsibility of providing its services to external code (the injector). The client is not allowed to call the injector code;[2] it is the injector that constructs the services. The injector then injects (passes) the services into the client which might already exist or may also be constructed by the injector. The client then uses the services. This means the client does not need to know about the injector, how to construct the services, or even which actual services it is using. The client only needs to know about the intrinsic interfaces of the services because these define how the client may use the services. This separates the responsibility of "use" from the responsibility of "construction".
Uses
Dependency Injection solves problems such as:[3]
- How can an application or class be independent of how its objects are created?
- How can the way objects are created be specified in separate configuration files?
- How can an application support different configurations?
Creating objects directly within the class can often be inflexible because it commits the class to particular objects and implementations. This can make it difficult to change the instantiation at runtime, especially in compiled languages where changing the underlying objects can sometimes require re-compiling the source code.
With Dependency Injection the class is no longer responsible for instantiating the objects it requires. Those responsiblities are passed to independent services.
Overview
When you go and get things out of the refrigerator for yourself, you can cause problems. You might leave the door open, you might get something Mommy or Daddy don't want you to have. You might even be looking for something we don't even have or which has expired.
What you should be doing is stating a need, "I need something to drink with lunch," and then we will make sure you have something when you sit down to eat.Dependency injection separates the creation of a client's dependencies from the client's behavior, which allows program designs to be loosely coupled[7] and to follow the dependency inversion and single responsibility principles.[4][8] It directly contrasts with the service locator pattern, which allows clients to know about the system they use to find dependencies.
An injection, the basic unit of dependency injection, is not a new or a custom mechanism. It works in the same way that "parameter passing" works.[9] Referring to "parameter passing" as an injection carries the added implication that it is being done to isolate the client from details.
An injection is also about what is in control of the passing (never the client) and is independent of how the passing is accomplished, whether by passing a reference or a value.
Dependency injection involves four roles:
- the service object(s) to be used
- the client object that is depending on the service(s) it uses
- the interfaces that define how the client may use the services
- the injector, which is responsible for constructing the services and injecting them into the client
As an analogy,
- service - an electric, gas, hybrid, or diesel car
- client - a driver who uses the car the same way regardless of the engine
- interface - automatic, ensures driver does not have to understand details of shifting gears
- injector - the parent who bought the kid the car and decided which kind
Any object that may be used can be considered a service. Any object that uses other objects can be considered a client. The names have nothing to do with what the objects are for and everything to do with the role the objects play in any one injection.
The interfaces are the types the client expects its dependencies to be. An issue is what they make accessible. They may truly be interface types implemented by the services but also may be abstract classes or even the concrete services themselves, though this last would violate DIP[10] and sacrifice the dynamic decoupling that enables testing. It is only required that the client does not know which they are and therefore never treats them as concrete, say by constructing or extending them.
The client should have no concrete knowledge of the specific implementation of its dependencies. It should only know the interface's name and API. As a result, the client will not need to change even if what is behind the interface changes. However, if the interface is refactored from being a class to an interface type (or vice versa) the client will need to be recompiled.[11] This is significant if the client and services are published separately. This unfortunate coupling is one that dependency injection cannot resolve.
The injector introduces the services into the client. Often, it also constructs the client. An injector may connect together a very complex object graph by treating an object like a client and later as a service for another client. The injector may actually be many objects working together but may not be the client. The injector may be referred to by other names such as: assembler, provider, container, factory, builder, spring, construction code, or main.
Dependency injection can be applied as a discipline, one that asks that all objects separate construction and behavior. Relying on a DI framework to perform construction can lead to forbidding the use of the new keyword, or, less strictly, only allowing direct construction of value objects.[12][13][14][15]
Taxonomy
Inversion of control (IoC) is more general than dependency injection. Put simply, IoC means letting other code call you rather than insisting on doing the calling. An example of IoC without dependency injection is the template method pattern. Here, polymorphism is achieved through subclassing, that is, inheritance.[16]
Dependency injection implements IoC through composition so is often identical to that of the strategy pattern, but while the strategy pattern is intended for dependencies to be interchangeable throughout an object's lifetime, in dependency injection it may be that only a single instance of a dependency is used.[17] This still achieves polymorphism, but through delegation and composition.
Dependency injection frameworks
Application frameworks such as CDI and its implementation Weld, Spring, Guice, Play framework, Salta, Glassfish HK2, Dagger, and Managed Extensibility Framework (MEF) support dependency injection but are not required to do dependency injection.[18][19]
Advantages
- Dependency injection allows a client the flexibility of being configurable. Only the client's behavior is fixed. The client may act on anything that supports the intrinsic interface the client expects.[20]
- Dependency injection can be used to externalize a system's configuration details into configuration files, allowing the system to be reconfigured without recompilation. Separate configurations can be written for different situations that require different implementations of components. This includes, but is not limited to, testing.[21]
- Because dependency injection does not require any change in code behavior it can be applied to legacy code as a refactoring. The result is clients that are more independent and that are easier to unit test in isolation using stubs or mock objects that simulate other objects not under test. This ease of testing is often the first benefit noticed when using dependency injection.[22]
- Dependency injection allows a client to remove all knowledge of a concrete implementation that it needs to use. This helps isolate the client from the impact of design changes and defects. It promotes reusability, testability and maintainability.[23]
- Reduction of boilerplate code in the application objects, since all work to initialize or set up dependencies is handled by a provider component.[23]
- Dependency injection allows concurrent or independent development. Two developers can independently develop classes that use each other, while only needing to know the interface the classes will communicate through. Plugins are often developed by third party shops that never even talk to the developers who created the product that uses the plugins.[24]
- Dependency Injection decreases coupling between a class and its dependency.[25][26]
Disadvantages
- Dependency injection creates clients that demand configuration details be supplied by construction code. This can be onerous when obvious defaults are available.[27]
- Dependency injection can make code difficult to trace (read) because it separates behavior from construction. This means developers must refer to more files to follow how a system performs.[28]
- Dependency injection frameworks are implemented with reflection or dynamic programming. This can hinder use of IDE automation, such as "find references", "show call hierarchy" and safe refactorings.[29]
- Dependency injection typically requires more upfront development effort since one can not summon into being something right when and where it is needed but must ask that it be injected and then ensure that it has been injected.[30]
- Dependency injection forces complexity to move out of classes and into the linkages between classes which might not always be desirable or easily managed.[31]
- Dependency injection can encourage dependence on a dependency injection framework.[31][32][33]
Structure
UML class and sequence diagram
In the above UML class diagram, the Client
class
that requires ServiceA
and ServiceB
objects does not instantiate the ServiceA1
and ServiceB1
classes directly.
Instead, an Injector
class creates the objects and injects them
into the Client
, which makes the Client
independent of how the objects are created (which concrete classes are instantiated).
The UML sequence diagram shows the run-time interactions: The Injector
object creates the ServiceA1
and ServiceB1
objects.
Thereafter, the Injector
creates the Client
object
and injects the ServiceA1
and ServiceB1
objects.
Examples
Without dependency injection
In the following Java example, the Client class contains a Service member variable that is initialized by the Client constructor. The client controls which implementation of service is used and controls its construction. In this situation, the client is said to have a hard-coded dependency on ExampleService.
// An example without dependency injection
public class Client {
// Internal reference to the service used by this client
private ExampleService service;
// Constructor
Client() {
// Specify a specific implementation in the constructor instead of using dependency injection
service = new ExampleService();
}
// Method within this client that uses the services
public String greet() {
return "Hello " + service.getName();
}
}
Dependency injection is an alternative technique to initialize the member variable rather than explicitly creating a service object as shown above. We can adjust this example using the various techniques described and illustrated in the subsections below.
Types of dependency injection
There are at least three ways a client object can receive a reference to an external module:[35]
- constructor injection
- The dependencies are provided through a client's class constructor.
- setter injection
- The client exposes a setter method that the injector uses to inject the dependency.
- interface injection
- The dependency's interface provides an injector method that will inject the dependency into any client passed to it. Clients must implement an interface that exposes a setter method that accepts the dependency.
Other types
It is possible for DI frameworks to have other types of injection beyond those presented above.[36]
Testing frameworks may also use other types. Some modern testing frameworks do not even require that clients actively accept dependency injection, thus making legacy code testable. In particular, in the Java language, it is possible to use reflection to make private attributes public when testing and thus accept injections by assignment.[37]
Some attempts at Inversion of Control do not provide full removal of dependency, but instead simply substitute one form of dependency for another. As a rule of thumb, if a programmer can look at nothing but the client code and tell what framework is being used, then the client has a hard-coded dependency on the framework.
Constructor injection
This method requires the client to provide a parameter in a constructor for the dependency.
// Constructor
Client(Service service) {
// Save the reference to the passed-in service inside this client
this.service = service;
}
Setter injection
This method requires the client to provide a setter method for the dependency.
// Setter method
public void setService(Service service) {
// Save the reference to the passed-in service inside this client.
this.service = service;
}
Interface injection
This is simply the client publishing a role interface to the setter methods of the client's dependencies. It can be used to establish how the injector should talk to the client when injecting dependencies.
// Service setter interface.
public interface ServiceSetter {
public void setService(Service service);
}
// Client class
public class Client implements ServiceSetter {
// Internal reference to the service used by this client.
private Service service;
// Set the service that this client is to use.
@Override
public void setService(Service service) {
this.service = service;
}
}
Constructor injection comparison
Preferred when all dependencies can be constructed first because it can be used to ensure the client object is always in a valid state, as opposed to having some of its dependency references be null (not be set). However, on its own, it lacks the flexibility to have its dependencies changed later. This can be a first step towards making the client immutable and therefore thread safe.
// Constructor
Client(Service service, Service otherService) {
if (service == null) {
throw new InvalidParameterException("service must not be null");
}
if (otherService == null) {
throw new InvalidParameterException("otherService must not be null");
}
// Save the service references inside this client
this.service = service;
this.otherService = otherService;
}
Setter injection comparison
Requires the client to provide a setter method for each dependency. This gives the freedom to manipulate the state of the dependency references at any time. This offers flexibility, but if there is more than one dependency to be injected, it is difficult for the client to ensure that all dependencies are injected before the client could be provided for use.
// Set the service to be used by this client
public void setService(Service service) {
if (service == null) {
throw new InvalidParameterException("service must not be null");
}
this.service = service;
}
// Set the other service to be used by this client
public void setOtherService(Service otherService) {
if (otherService == null) {
throw new InvalidParameterException("otherService must not be null");
}
this.otherService = otherService;
}
Because these injections happen independently, there is no way to tell when the injector is finished wiring the client. A dependency can be left null simply by the injector failing to call its setter. This forces the check that injection was completed from when the client is assembled to whenever it is used.
// Set the service to be used by this client
public void setService(Service service) {
this.service = service;
}
// Set the other service to be used by this client
public void setOtherService(Service otherService) {
this.otherService = otherService;
}
// Check the service references of this client
private void validateState() {
if (service == null) {
throw new IllegalStateException("service must not be null");
}
if (otherService == null) {
throw new IllegalStateException("otherService must not be null");
}
}
// Method that uses the service references
public void doSomething() {
validateState();
service.doYourThing();
otherService.doYourThing();
}
Interface injection comparison
The advantage of interface injection is that dependencies can be completely ignorant of their clients yet can still receive a reference to a new client and, using it, send a reference-to-self back to the client. In this way, the dependencies become injectors. The key is that the injecting method (which could just be a classic setter method) is provided through an interface.
An assembler is still needed to introduce the client and its dependencies. The assembler would take a reference to the client, cast it to the setter interface that sets that dependency, and pass it to that dependency object which would turn around and pass a reference-to-self back to the client.
For interface injection to have value, the dependency must do something in addition to simply passing back a reference to itself. This could be acting as a factory or sub-assembler to resolve other dependencies, thus abstracting some details from the main assembler. It could be reference-counting so that the dependency knows how many clients are using it. If the dependency maintains a collection of clients, it could later inject them all with a different instance of itself.
// Service setter interface.
public interface ServiceSetter {
public void setService(Service service);
}
// Client class
public class Client implements ServiceSetter {
// Internal reference to the service used by this client.
private Service service;
// Set the service that this client is to use.
@Override
public void setService(Service service) {
this.service = service;
}
}
// Injector class
public class ServiceInjector {
Set<ServiceSetter> clients;
public void inject(ServiceSetter client) {
clients.add(client);
client.setService(new ServiceFoo());
}
public void switchToBar() {
for (Client client : clients) {
client.setService(new ServiceBar());
}
}
}
// Service classes
public class ServiceFoo implements Service {}
public class ServiceBar implements Service {}
Assembling examples
Manually assembling in main by hand is one way of implementing dependency injection.
public class Injector {
public static void main(String[] args) {
// Build the dependencies first
Service service = new ExampleService();
// Inject the service, constructor style
Client client = new Client(service);
// Use the objects
System.out.println(client.greet());
}
}
The example above constructs the object graph manually and then invokes it at one point to start it working. Important to note is that this injector is not pure. It uses one of the objects it constructs. It has a purely construction-only relationship with ExampleService but mixes construction and using of Client. This should not be common. It is, however, unavoidable. Just like object oriented software needs a non-object oriented static method like main() to get started, a dependency injected object graph needs at least one (preferably only one) entry point to get the whole thing started.
Manual construction in the main method may not be this straight forward and may involve calling builders, factories, or other construction patterns as well. This can be fairly advanced and abstract. The line is crossed from manual dependency injection to framework dependency injection once the constructing code is no longer custom to the application and is instead universal.[38]
Frameworks like Spring can construct these same objects and wire them together before returning a reference to client. All mention of the concrete ExampleService can be moved from the code to the configuration data.
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Injector {
public static void main(String[] args) {
// -- Assembling objects -- //
BeanFactory beanfactory = new ClassPathXmlApplicationContext("Beans.xml");
Client client = (Client) beanfactory.getBean("client");
// -- Using objects -- //
System.out.println(client.greet());
}
}
Frameworks like Spring allow assembly details to be externalized in configuration files. This code (above) constructs objects and wires them together according to Beans.xml (below). ExampleService is still constructed even though it is only mentioned below. A long and complex object graph can be defined this way and the only class mentioned in code would be the one with the entry point method, which in this case is greet().
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="service" class="ExampleService">
</bean>
<bean id="client" class="Client">
<constructor-arg value="service" />
</bean>
</beans>
In the example above Client and Service have not had to undergo any changes to be provided by Spring. They are allowed to remain simple POJOs.[39][40][41] This shows how Spring can connect services and clients that are completely ignorant of its existence. This could not be said if Spring annotations were added to the classes. By keeping Spring-specific annotations and calls from spreading out among many classes, the system stays only loosely dependent on Spring.[32] This can be important if the system intends to outlive Spring.
The choice to keep POJOs pure does not come without cost. Rather than spending the effort to develop and maintain complex configuration files, it is possible to simply use annotations to mark classes and let Spring do the rest of the work. Resolving dependencies can be simple if they follow a convention such as matching by type or by name. This is choosing convention over configuration.[42] It is also arguable that, when refactoring to another framework, removing framework specific annotations would be a trivial part of the task[43] and many injection annotations are now standardized.[44][45]
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Injector {
public static void main(String[] args) {
// Assemble the objects
BeanFactory beanfactory = new AnnotationConfigApplicationContext(MyConfiguration.class);
Client client = beanfactory.getBean(Client.class);
// Use the objects
System.out.println(client.greet());
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan
public class MyConfiguration {
@Bean
public Client client(ExampleService service) {
return new Client(service);
}
}
@Component
public class ExampleService {
public String getName() {
return "World!";
}
}
Assembly comparison
The different injector implementations (factories, service locators, and dependency injection containers) are not that different as far as dependency injection is concerned. What makes all the difference is where they are allowed to be used. Move calls to a factory or a service locator out of the client and into main and suddenly main makes a fairly good dependency injection container.
By moving all knowledge of the injector out, a clean client, free of knowledge of the outside world, is left behind. However, any object that uses other objects can be considered a client. The object that contains main is no exception. This main object is not using dependency injection. It is actually using the service locator pattern. This can not be avoided because the choice of service implementations must be made somewhere.
Externalizing the dependencies into configuration files does not change this fact. What makes this reality part of a good design is that the service locator is not spread throughout the code base. It is confined to one place per application. This leaves the rest of the code base free to use dependency injection to make clean clients.
Dependency Injection Pattern
The examples until now have been overly simple examples about constructing a string. However, the dependency injection pattern is most useful when constructing an object graph where objects communicate via messages. Objects constructed in main will last for the life of the program. The typical pattern is to construct the graph and then call one method on one object to send the flow of control into the object graph. Just as main is the entry point to the static code, this one method is the entry point to the applications non-static code.
public static void main(String[] args) throws IOException {
// Construction code.
Greeter greeter = new Greeter(System.out); // This may be many lines that connect many objects
// Behavior code.
greeter.greet(); // This is one call to one method on one object in the object graph
}
class Greeter {
public void greet() {
this.out.println("Hello world!");
}
public Greeter(PrintStream out) {
this.out = out;
}
private PrintStream out;
}
AngularJS example
In the AngularJS framework, there are only three ways a component (object or function) can directly access its dependencies:
- The component can create the dependency, typically using the
new
operator. - The component can look up the dependency, by referring to a global variable.
- The component can have the dependency passed to it where it is needed.
The first two options of creating or looking up dependencies are not optimal because they hard code the dependency to the component. This makes it difficult, if not impossible, to modify the dependencies. This is especially problematic in tests, where it is often desirable to provide mock dependencies for test isolation.
The third option is the most viable, since it removes the responsibility of locating the dependency from the component. The dependency is simply handed to the component.
function SomeClass(greeter) {
this.greeter = greeter;
}
SomeClass.prototype.doSomething = function(name) {
this.greeter.greet(name);
}
In the above example, SomeClass
is not concerned with creating or locating the greeter dependency, it is simply handed the greeter when it is instantiated.
This is desirable, but it puts the responsibility of getting hold of the dependency on the code that constructs SomeClass
.
To manage the responsibility of dependency creation, each AngularJS application has an injector. The injector is a service locator that is responsible for construction and look-up of dependencies.
Here is an example of using the injector service:
// Provide the wiring information in a module
var myModule = angular.module('myModule', []);
// Teach the injector how to build a greeter service.
// greeter is dependent on the $window service.
// The greeter service is an object that
// contains a greet method.
myModule.factory('greeter', function($window) {
return {
greet: function(text) {
$window.alert(text);
}
};
});
Create a new injector that can provide components defined in the myModule
module and request our greeter service from the injector. (This is usually done automatically by the AngularJS bootstrap).
var injector = angular.injector(['myModule', 'ng']);
var greeter = injector.get('greeter');
Asking for dependencies solves the issue of hard coding, but it also means that the injector needs to be passed throughout the application. Passing the injector breaks the Law of Demeter. To remedy this, we use a declarative notation in our HTML templates, to hand the responsibility of creating components over to the injector, as in this example:
<div ng-controller="MyController">
<button ng-click="sayHello()">Hello</button>
</div>
function MyController($scope, greeter) {
$scope.sayHello = function() {
greeter.greet('Hello World');
};
}
When AngularJS compiles the HTML, it processes the ng-controller
directive, which in turn asks the injector to create an instance of the controller and its dependencies.
injector.instantiate(MyController);
This is all done behind the scenes. Because the ng-controller
defers to the injector to instantiate the class, it can satisfy all of the dependencies of MyController
without the controller ever knowing about the injector. The application code simply declares the dependencies it needs, without having to deal with the injector. This setup does not break the Law of Demeter.
C#
Example of the Constructor injection, Setter injection and Interface injection on C#
using System;
namespace DependencyInjection
{
// An interface for the library
interface IGamepadFunctionality
{
String GetGamepadName();
void SetVibrationPower(float InPower);
}
// Concrete implementation of the xbox controller functionality
class XBoxGamepad : IGamepadFunctionality
{
readonly String GamepadName = "XBox Controller";
float VibrationPower = 1.0f;
public String GetGamepadName() => GamepadName;
public void SetVibrationPower(float InPower) => VibrationPower = Math.Clamp(InPower, 0.0f, 1.0f);
}
// Concrete implementation of the playstation controller functionality
class PlaystationJoystick : IGamepadFunctionality
{
readonly String ControllerName = "Playstation controller";
float VibratingPower = 100.0f;
public String GetGamepadName() => ControllerName;
public void SetVibrationPower(float InPower) => VibratingPower = Math.Clamp(InPower * 100.0f, 0.0f, 100.0f);
}
// Concrete implementation of the steam controller functionality
class SteamController : IGamepadFunctionality
{
readonly String JoystickName = "Steam controller";
double Vibrating = 1.0;
public String GetGamepadName() => JoystickName;
public void SetVibrationPower(float InPower) => Vibrating = Convert.ToDouble(Math.Clamp(InPower, 0.0f, 1.0f));
}
// An interface for gamepad functionality injections
interface IGamepadFunctionalityInjector
{
void InjectFunctionality(IGamepadFunctionality InGamepadFunctionality);
}
class CGamepad : IGamepadFunctionalityInjector
{
IGamepadFunctionality _GamepadFunctionality;
public CGamepad()
{
}
// Constructor injection
public CGamepad(IGamepadFunctionality InGamepadFunctionality) => _GamepadFunctionality = InGamepadFunctionality;
// Setter injection
public void SetGamepadFunctionality(IGamepadFunctionality InGamepadFunctionality) => _GamepadFunctionality = InGamepadFunctionality;
// Interface injection
public void InjectFunctionality(IGamepadFunctionality InGamepadFunctionality) => _GamepadFunctionality = InGamepadFunctionality;
public void Showcase()
{
String Message = String.Format("We're using the {0} right now, do you want to change the vibrating power?\r\n", _GamepadFunctionality.GetGamepadName());
Console.WriteLine(Message);
}
}
enum EPlatforms: byte
{
Xbox,
Playstation,
Steam
}
class CGameEngine
{
EPlatforms _Platform;
CGamepad _Gamepad;
public void SetPlatform(EPlatforms InPlatform)
{
_Platform = InPlatform;
switch(_Platform)
{
case EPlatforms.Xbox:
// injects dependency on XBoxGamepad class through Constructor Injection
_Gamepad = new CGamepad(new XBoxGamepad());
break;
case EPlatforms.Playstation:
_Gamepad = new CGamepad();
// injects dependency on PlaystationJoystick class through Setter Injection
_Gamepad.SetGamepadFunctionality(new PlaystationJoystick());
break;
case EPlatforms.Steam:
_Gamepad = new CGamepad();
// injects dependency on SteamController class through Interface Injection
_Gamepad.InjectFunctionality(new SteamController());
break;
}
_Gamepad.Showcase();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
CGameEngine Engine = new CGameEngine();
Engine.SetPlatform(EPlatforms.Steam);
Engine.SetPlatform(EPlatforms.Xbox);
Engine.SetPlatform(EPlatforms.Playstation);
}
}
}
See also
References
- I.T., Titanium. "James Shore: Dependency Injection Demystified". www.jamesshore.com. Retrieved 2015-07-18.
- "HollywoodPrinciple". c2.com. Retrieved 2015-07-19.
- "The Dependency Injection design pattern - Problem, Solution, and Applicability". w3sDesign.com. Retrieved 2017-08-12.
- Seeman, Mark (October 2011). Dependency Injection in .NET. Manning Publications. p. 4. ISBN 9781935182504.
- "Dependency Injection in NET" (PDF). philkildea.co.uk. p. 4. Retrieved 2015-07-18.
- "How to explain dependency injection to a 5-year-old?". stackoverflow.com. Retrieved 2015-07-18.
- Seemann, Mark. "Dependency Injection is Loose Coupling". blog.ploeh.dk. Retrieved 2015-07-28.
- Niko Schwarz, Mircea Lungu, Oscar Nierstrasz, “Seuss: Decoupling responsibilities from static methods for fine-grained configurability”, Journal of Object Technology, Volume 11, no. 1 (April 2012), pp. 3:1-23
- "Passing Information to a Method or a Constructor (The Java™ Tutorials > Learning the Java Language > Classes and Objects)". docs.oracle.com. Retrieved 2015-07-18.
- "A curry of Dependency Inversion Principle (DIP), Inversion of Control (IoC), Dependency Injection (DI) and IoC Container - CodeProject". www.codeproject.com. Retrieved 2015-08-08.
- "How to force "program to an interface" without using a java Interface in java 1.6". programmers.stackexchange.com. Retrieved 2015-07-19.
- "To "new" or not to "new"…". Retrieved 2015-07-18.
- "How to write testable code". www.loosecouplings.com. Retrieved 2015-07-18.
- "Writing Clean, Testable Code". www.ethanresnick.com. Retrieved 2015-07-18.
- Sironi, Giorgio. "When to inject: the distinction between newables and injectables - Invisible to the eye". www.giorgiosironi.com. Retrieved 2015-07-18.
- "Inversion of Control vs Dependency Injection". stackoverflow.com. Retrieved 2015-08-05.
- "What is the difference between Strategy pattern and Dependency Injection?". stackoverflow.com. Retrieved 2015-07-18.
- "Dependency Injection != using a DI container". www.loosecouplings.com. Retrieved 2015-07-18.
- "Black Sheep » DIY-DI » Print". blacksheep.parry.org. Archived from the original on 2015-06-27. Retrieved 2015-07-18.
- https://python.astrotech.io/design-patterns/structural/dependency-injection.html
- http://python-dependency-injector.ets-labs.org/introduction/di_in_python.html
- https://visualstudiomagazine.com/articles/2014/07/01/larger-applications.aspx
- "The Java Community Process(SM) Program - JSRs: Java Specification Requests - detail JSR# 330". jcp.org. Retrieved 2015-07-18.
- https://dzone.com/articles/how-dependency-injection-di-works-in-spring-java-a
- "the urban canuk, eh: On Dependency Injection and Violating Encapsulation Concerns". www.bryancook.net. Retrieved 2015-07-18.
- "The Dependency Injection Design Pattern". msdn.microsoft.com. Retrieved 2015-07-18.
- https://dzone.com/articles/how-dependency-injection-di-works-in-spring-java-a
- https://dzone.com/articles/how-dependency-injection-di-works-in-spring-java-a
- https://www.freecodecamp.org/news/a-quick-intro-to-dependency-injection-what-it-is-and-when-to-use-it-7578c84fa88f/
- https://www.professionalqa.com/dependency-injection
- "What are the downsides to using Dependency Injection?". stackoverflow.com. Retrieved 2015-07-18.
- "Dependency Injection Inversion - Clean Coder". sites.google.com. Retrieved 2015-07-18.
- "Decoupling Your Application From Your Dependency Injection Framework". InfoQ. Retrieved 2015-07-18.
- "The Dependency Injection design pattern - Structure and Collaboration". w3sDesign.com. Retrieved 2017-08-12.
- Martin Fowler (2004-01-23). "Inversion of Control Containers and the Dependency Injection pattern - Forms of Dependency Injection". Martinfowler.com. Retrieved 2014-03-22.
- "Yan - Dependency Injection Types". Yan.codehaus.org. Archived from the original on 2013-08-18. Retrieved 2013-12-11.
- "AccessibleObject (Java Platform SE 7)". docs.oracle.com. Retrieved 2015-07-18.
- Riehle, Dirk (2000), Framework Design: A Role Modeling Approach (PDF), Swiss Federal Institute of Technology
- "Spring Tips: A POJO with annotations is not Plain". Archived from the original on 2015-07-15. Retrieved 2015-07-18.
- "Annotations in POJO – a boon or a curse? | Techtracer". 2007-04-07. Retrieved 2015-07-18.
- Pro Spring Dynamic Modules for OSGi Service Platforms. APress. 2009-02-17. ISBN 9781430216124. Retrieved 2015-07-06.
- "Captain Debug's Blog: Is 'Convention Over Configuration' Going Too Far?". www.captaindebug.com. Retrieved 2015-07-18.
- Decker, Colin. "What's the issue with @Inject? | Colin's Devlog". blog.cgdecker.com. Retrieved 2015-07-18.
- Morling, Gunnar (2012-11-18). "Dagger - A new Java dependency injection framework". Dagger - A new Java dependency injection framework - Musings of a Programming Addict. Retrieved 2015-07-18.
- "The Java Community Process(SM) Program - JSRs: Java Specification Requests - detail JSR# 330". www.jcp.org. Retrieved 2015-07-18.
External links
Wikimedia Commons has media related to Dependency injection. |
- Composition Root by Mark Seemann
- A beginners guide to Dependency Injection
- 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
- Martin Fowler's original article that introduced the term Dependency Injection
- P of EAA: Plugin
- The Rich Engineering Heritage Behind Dependency Injection - Andrew McVeigh - A detailed history of dependency injection.
- What is Dependency Injection? - An alternative explanation - Jakob Jenkov
- Writing More Testable Code with Dependency Injection -- Developer.com, October 2006
- Managed Extensibility Framework Overview -- MSDN
- Old fashioned description of the Dependency Mechanism by Hunt 1998
- Refactor Your Way to a Dependency Injection Container
- Understanding DI in PHP
- You Don't Need a Dependency Injection Container