Dependency injection: Difference between revisions

Content deleted Content added
replaced: it's → its
Line 6:
Dependency injection is often used to keep code in-line with the [[dependency inversion principle]].<ref>{{Cite web |last=Erez |first=Guy |date=2022-03-09 |title=Dependency Inversion vs. Dependency Injection |url=https://betterprogramming.pub/straightforward-simple-dependency-inversion-vs-dependency-injection-7d8c0d0ed28e |access-date=2022-12-06 |website=Medium |language=en}}</ref><ref>{{Cite web |last=Mathews |first=Sasha |date=2021-03-25 |title=You are Simply Injecting a Dependency, Thinking that You are Following the Dependency Inversion… |url=https://levelup.gitconnected.com/you-are-simply-injecting-a-dependency-thinking-that-you-are-following-the-dependency-inversion-32632954c208 |access-date=2022-12-06 |website=Medium |language=en }}</ref>
 
In [[Staticallystatically typed language|statically typed languages]]s using dependency injection means a client only needs to declare the [[Interface (computing)|interfaces]] of the services it uses, rather than their concrete implementations, making it easier to change which services are used at runtime without recompiling.
 
Application frameworks often combine dependency injection with [[inversion of control]]. Under inversion of control, the framework first constructs an object (such as a controller), and then passes [[control flow]] to it. With dependency injection, the framework also instantiates the dependencies declared by the application object (often in the constructor method's parameters), and passes the dependencies into the object.<ref>{{cite web |title=Spring IoC Container |url=https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/beans.html |access-date=2023-05-23 |language=en }}</ref>
 
Dependency injection implements the idea of "inverting control over the implementations of dependencies", which is why certain Java frameworks generically name the concept "inversion of control" (not to be confused with [[Inversion_of_controlInversion of control|inversion of control flow]]).<ref name="FowlerDI-IOC">{{cite web |last1=Fowler |first1=Martin |title=Inversion of Control Containers and the Dependency Injection pattern |url=https://martinfowler.com/articles/injection.html#InversionOfControl |website=MartinFowler.com |access-date=4 June 2023}}</ref>
 
== Roles ==
Line 32:
 
=== Interfaces ===
Clients should not know how their dependencies are implemented, only their names and [[Application programming interface|API]]. A service which retrieves [[Email|emailsemail]]s, for instance, may use the [[Internet_Message_Access_ProtocolInternet Message Access Protocol|IMAP]] or [[Post Office Protocol|POP3]] protocols behind the scenes, but this detail is likely irrelevant to calling code that merely wants an email retrieved. By ignoring implementation details, clients do not need to change when their dependencies do.
 
=== Injectors ===
The '''injector''', sometimes also called an assembler, container, provider or factory, introduces services to the client.
 
The role of injectors is to construct and connect complex object graphs, where objects may be both clients and services. The injector itself may be many objects working together, but must not be the client, as this would create a [[circular dependency]].
Line 42:
 
=== Analogy ===
As an analogy, [[Car|carscar]]s can be thought of as services which perform the useful work of transporting people from one place to another. Car engines can require [[Gasoline|gas]], [[Diesel fuel|diesel]] or [[Electric car|electricity]], but this detail is unimportant to the client—a driver—who only cares if it can get them to their destination.
 
Cars present a uniform interface through their pedals, steering wheels and other controls. As such, which engine they were 'injected' with on the factory line ceases to matter and drivers can switch between any kind of car as needed.
 
== Advantages and disadvantages ==
 
=== Advantages ===
A basic benefit of dependency injection is decreased coupling between classes and their dependencies.<ref>{{Cite web|title=the urban canuk, eh: On Dependency Injection and Violating Encapsulation Concerns|url=http://www.bryancook.net/2011/08/on-dependency-injection-and-violating.html|access-date=2015-07-18|website=www.bryancook.net}}</ref><ref>{{Cite web|title=The Dependency Injection Design Pattern|url=https://msdn.microsoft.com/en-us/library/vstudio/hh323705(v=vs.100).aspx|access-date=2015-07-18|website=msdn.microsoft.com}}</ref>
 
By removing a client's knowledge of how its dependencies are implemented, programs become more reusable, testable and maintainable.<ref name="JSR330">{{Cite web|title=The Java Community Process(SM) Program - JSRs: Java Specification Requests - detail JSR# 330|url=https://jcp.org/en/jsr/detail?id=330|access-date=2015-07-18|website=jcp.org}}</ref>
 
This also results in increased flexibility: a client may act on anything that supports the intrinsic interface the client expects.<ref>{{cite web |url=https://python.astrotech.io/design-patterns/structural/dependency-injection.html |url-status=dead |archive-url=https://web.archive.org/web/20200208005839/http://python.astrotech.io/design-patterns/structural/dependency-injection.html |archive-date=2020-02-08 |title=3.1. Dependency injection — Python 3: from None to Machine Learning}}</ref>
Line 62:
Many of dependency injection's benefits are particularly relevant to [[Unit testing|unit-testing]].
 
For example, 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.<ref>{{Cite web|url=http://python-dependency-injector.ets-labs.org/introduction/di_in_python.html|title = Dependency injection and inversion of control in Python — Dependency Injector 4.36.2 documentation}}</ref>
 
Similarly, because dependency injection does not require any change in code behavior, it can be applied to legacy code as a [[Code refactoring|refactoring]]. This makes clients more independent and are easier to [[Unit testing|unit test]] in isolation, using [[Method stub|stubs]] or [[mock object]]s, that simulate other objects not under test.
 
This ease of testing is often the first benefit noticed when using dependency injection.<ref>{{Cite web|url=https://visualstudiomagazine.com/articles/2014/07/01/larger-applications.aspx |title = How to Refactor for Dependency Injection, Part 3: Larger Applications }}</ref>
Line 115:
 
=== Setter injection ===
By accepting dependencies through a [[setter method]], rather than a constructor, clients can allow injectors to manipulate their dependencies at any time. This offers flexibility, but makes it difficult to ensure that all dependencies are injected and valid before the client is used.
 
<syntaxhighlight lang="java">
Line 196:
</syntaxhighlight>
 
Manual construction may be more complex and involve [[Builder pattern|builders]], [[Factory (object-oriented programming)|factories]], or other [[Creational pattern|construction patterns]].
 
=== Frameworks ===
Line 208:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
 
public class Injector {
Line 402 ⟶ 401:
</syntaxhighlight>
 
Then, you can access the private fields of the [[Record (computer science)|struct]] in any method that is it'sits [[Pointer (computer programming)|pointer]] receiver, without violating encapsulation.
<syntaxhighlight lang="go">
package users