Dependency injection: Difference between revisions

Content deleted Content added
Licriss (talk | contribs)
m Grammatical change for clarity of implicit info
Tags: Visual edit Mobile edit Mobile web edit
Xilef97 (talk | contribs)
m C++: fix typo: wrong type was used for the member variable, code wouldn't compile
 
(40 intermediate revisions by 29 users not shown)
Line 1:
{{Short description|Software programming technique}}
[[File:DependencyInjectionServiceProvider.png|alt=A diagram of an archetypical dependency injection container for the .NET platform.|thumb|Dependency injection is often used alongside specialized frameworks, known as 'containers', to facilitate program composition.]]
[[File:Dependency injection example app.svg|thumb|PetManager gets injected into PetController and PetRepository gets injected into PetManager]]
In [[software engineering]], '''dependency injection''' is a programming technique in which an [[Object (computer science)|object]] or [[Subroutine|function]] receives other objects or functions that it depends on. Dependency injection aims to [[separation of concerns|separate the concerns]] of constructing objects and using them, leading to [[Loose coupling|loosely]] [[Coupling (computer programming)|coupled]] programs.<ref>{{Cite web |last=Seemann |first=Mark |title=Dependency Injection is Loose Coupling |url=http://blog.ploeh.dk/2010/04/07/DependencyInjectionisLooseCoupling/ |access-date=2015-07-28 |website=blog.ploeh.dk}}</ref><ref name="MarkSeeman2011P4" /><ref>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</ref> The pattern ensures that an object or function which wants to use a given [[Service (systems architecture)|service]] should not have to know how to construct those services. Instead, the receiving '[[Client (computing)|client]]' (object or function) is provided with its dependencies by external code (an 'injector'), which it is not aware of.<ref name="HollywoodPrinciple.c2">{{Cite web |title=HollywoodPrinciple |url=http://c2.com/cgi/wiki?HollywoodPrinciple |access-date=2015-07-19 |website=c2.com}}</ref> Dependency injection makes implicit dependencies explicit and helps solve the following problems:<ref>{{cite web |title=The Dependency Injection design pattern - Problem, Solution, and Applicability |url=http://w3sdesign.com/?gr=u01&ugr=proble |access-date=2017-08-12 |website=w3sDesign.com}}</ref>
In [[software engineering]], '''dependency injection''' is a programming technique in which an [[Object (computer science)|object]] or [[Subroutine|function]] receives other objects or functions that it requires, as opposed to creating them internally. Dependency injection aims to [[separation of concerns|separate the concerns]] of constructing objects and using them, leading to [[Loose coupling|loosely coupled]] programs.<ref>{{Cite web |last=Seemann |first=Mark |title=Dependency Injection is Loose Coupling |url=http://blog.ploeh.dk/2010/04/07/DependencyInjectionisLooseCoupling/ |access-date=2015-07-28 |website=blog.ploeh.dk}}</ref><ref name="MarkSeeman2011P4" /><ref>Niko Schwarz, Mircea Lungu, Oscar Nierstrasz, "Seuss: Decoupling responsibilities from static methods for fine-grained configurability", Journal of Object Technology, volume&nbsp;11, no.&nbsp;1 (April 2012), pp.&nbsp;3:1–23.</ref> The pattern ensures that an object or function that wants to use a given [[Service (systems architecture)|service]] should not have to know how to construct those services. Instead, the receiving "[[Client (computing)|client]]" (object or function) is provided with its dependencies by external code (an "injector"), which it is not aware of.<ref name="HollywoodPrinciple.c2">{{Cite web |title=HollywoodPrinciple |url=http://c2.com/cgi/wiki?HollywoodPrinciple |access-date=2015-07-19 |website=c2.com}}</ref> Dependency injection makes implicit dependencies explicit and helps solve the following problems:<ref>{{cite web |title=The Dependency Injection design pattern&nbsp;– Problem, Solution, and Applicability |url=http://w3sdesign.com/?gr=u01&ugr=proble |access-date=2017-08-12 |website=w3sDesign.com}}</ref>
* How can a [[Class (computer programming)|class]] be independent from the creation of the objects it depends on?
* How can an application, and the objects it uses support different configurations?
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>
* How can the behavior of a piece of code be changed without editing it directly?
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 that a client only needs to declaresdeclare the [[Interface (computing)|interfaces]] of the services it uses, rather than their concrete implementations, making it easier to change which services are actually used at runtime without recompiling.
 
Application frameworks often combine dependency injection with [[Inversion_of_control|Inversioninversion of Controlcontrol]]. Under inversion of control, the framework first constructs an application 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>{{Citecite 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 21:
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 something.
 
| source = John Munsch, 28 October 2009.<ref name=MarkSeeman2011P4>{{cite book|last1=Seeman|first1=Mark|title=Dependency Injection in .NET|date=October 2011|publisher=Manning Publications|isbn=9781935182504|page=4}}<!--|access-date=18 July 2015--></ref><ref>{{Cite web|title = Dependency Injection in NET|url = http://philkildea.co.uk/james/books/Dependency.Injection.in.NET.pdf|page = 4|website = philkildea.co.uk|access-date = 2015-07-18|archive-date = 2015-07-21|archive-url = https://web.archive.org/web/20150721171646/http://philkildea.co.uk/james/books/Dependency.Injection.in.NET.pdf|url-status = dead}}</ref><ref>{{Cite web|title = How to explain dependency injection to a 5-year-old?|url = https://stackoverflow.com/questions/1638919/how-to-explain-dependency-injection-to-a-5-year-old|website = stackoverflow.com|access-date = 2015-07-18}}</ref>
| align = right
| width = 33%
Line 33:
 
=== 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]].
 
Because dependency injection separates how objects are constructed from how they are used, it often diminishes the importance of the '''<code>new</code>''' keyword found in most [[Object-oriented programming|object-oriented languages]]. Because the framework handles creating services, the programmer tends to only directly construct [[value object]]s which represents entities in the program's ___domain (such as an <code>Employee</code> object in a business app or an <code>Order</code> object in a shopping app).<ref>{{Cite web |title=To "new" or not to "new"... |url=http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/ |access-date=2015-07-18 |archive-date=2020-05-13 |archive-url=https://web.archive.org/web/20200513185005/http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/ |url-status=dead }}</ref><ref>{{Cite web |title=How to write testable code |url=http://www.loosecouplings.com/2011/01/how-to-write-testable-code-overview.html |access-date=2015-07-18 |website=www.loosecouplings.com}}</ref><ref>{{Cite web |title=Writing Clean, Testable Code |url=http://www.ethanresnick.com/blog/testableCode.html |access-date=2015-07-18 |website=www.ethanresnick.com}}</ref><ref>{{Cite web |last=Sironi |first=Giorgio |title=When to inject: the distinction between newables and injectables - Invisible to the eye |url=http://www.giorgiosironi.com/2009/07/when-to-inject-distinction-between.html |access-date=2015-07-18 |website=www.giorgiosironi.com}}</ref>
 
=== 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—whopassenger—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 63:
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>
 
=== Disadvantages ===
Line 73:
* Creates clients that demand configuration details, which can be onerous when obvious defaults are available.<ref name="dzone.com" />
* Makes code difficult to trace because it separates behavior from construction.<ref name="dzone.com" />
* Is typically implemented with reflection or dynamic programming, hindering [[Integrated development environment|IDE]] automation.<ref>{{Citecite web |url=https://www.freecodecamp.org/news/a-quick-intro-to-dependency-injection-what-it-is-and-when-to-use-it-7578c84fa88f/ |title = A quick intro to Dependency Injection: What it is, and when to use it |date = 18 October 2018 }}</ref>
* Typically requires more upfront development effort.<ref>{{cite web |url=https://www.professionalqa.com/dependency-injection |title = Dependency Injection {{!}}Professionalqa.com }}</ref>
* Encourages dependence on a framework.<ref name="stackoverflow.com">{{Cite web |title=What are the downsides to using Dependency Injection? |url=https://stackoverflow.com/questions/2407540/what-are-the-downsides-to-using-dependency-injection |access-date=2015-07-18 |website=stackoverflow.com}}</ref><ref name="sites.google.com">{{Citecite web |title = Dependency Injection Inversion - Clean Coder |url = https://sites.google.com/site/unclebobconsultingllc/blogs-by-robert-martin/dependency-injection-inversion |website = sites.google.com |access-date = 2015-07-18 }}</ref><ref>{{Citecite web |title = Decoupling Your Application From Your Dependency Injection Framework |url = http://www.infoq.com/news/2010/01/dependency-injection-inversion |website = InfoQ |access-date = 2015-07-18 }}</ref>
 
== Types of dependency injection ==
There are three mainseveral ways in which a client can receive injected services:<ref>{{cite web|author=Martin Fowler |url=http://www.martinfowler.com/articles/injection.html#FormsOfDependencyInjection |title=Inversion of Control Containers and the Dependency Injection pattern - Forms of Dependency Injection |publisher=Martinfowler.com |date=2004-01-23 |access-date=2014-03-22 }}</ref>
* Constructor injection, where dependencies are provided through a client's class [[Constructor (object-oriented programming)|constructor]].
* Method Injection, where dependencies are provided to a method only when required for specific functionality.
* Setter injection, where the client exposes a setter method which accepts the dependency.
* Interface injection, where the dependency's interface provides an injector method that will inject the dependency into any client passed to it.
 
In some frameworks, clients do not need to actively accept dependency injection at all. In [[Java (programming language)|Java]], for example, reflection can make private attributes public when testing and inject services directly.<ref>{{Cite web |title=AccessibleObject (Java Platform SE 7) |url=http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/AccessibleObject.html |access-date=2015-07-18 |website=docs.oracle.com }}</ref>
 
=== Without dependency injection ===
Line 106 ⟶ 107:
 
// The dependency is injected through a constructor.
Client(final Service service) {
if (service == null) {
throw new IllegalArgumentException("service must not be null");
Line 113 ⟶ 114:
}
}
</syntaxhighlight>
 
=== Method Injection ===
Dependencies are passed as arguments to a specific method, allowing them to be used only during that method's execution without maintaining a long-term reference. This approach is particularly useful for temporary dependencies or when different implementations are needed for various method calls.
<syntaxhighlight lang="java">
public class Client {
public void performAction(Service service) {
if (service == null) {
throw new IllegalArgumentException("service must not be null");
}
service.execute();
}
}
 
</syntaxhighlight>
 
=== 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 123 ⟶ 138:
 
// The dependency is injected through a setter method.
public void setService(final Service service) {
if (service == null) {
throw new IllegalArgumentException("service must not be null");
Line 143 ⟶ 158:
<syntaxhighlight lang="java">
public interface ServiceSetter {
public void setService(Service service);
}
 
Line 150 ⟶ 165:
 
@Override
public void setService(final Service service) {
if (service == null) {
throw new IllegalArgumentException("service must not be null");
Line 159 ⟶ 174:
 
public class ServiceInjector {
private final Set<ServiceSetter> clients = new HashSet<>();
 
public void inject(final ServiceSetter client) {
this.clients.add(client);
client.setService(new ExampleService());
Line 167 ⟶ 182:
 
public void switch() {
for (final Client client : this.clients) {
client.setService(new AnotherExampleService());
}
Line 184 ⟶ 199:
public class Program {
 
public static void main(final String[] args) {
// Build the service.
final Service service = new ExampleService();
 
// Inject the service into the client.
final Client client = new Client(service);
 
// Use the objects.
Line 197 ⟶ 212:
</syntaxhighlight>
 
Manual construction may be more complex and involve [[Builder pattern|builders]], [[Factory (object-oriented programming)|factories]], or other [[Creational pattern|construction patterns]].
 
=== Frameworks ===
[[File:DependencyInjectionServiceProvider.png|alt=A class diagram of dependency injection containers in the .NET Framework.|thumb|Containers such as Ninject or StructureMap are commonly used in [[object-oriented programming]] languages to achieve Dependency Injection and [[inversion of control]].]]
Manual dependency injection is often tedious and error-prone for larger projects, promoting the use of frameworks which automate the process. Manual dependency injection becomes a dependency injection [[Software framework|framework]] once the constructing code is no longer custom to the application and is instead universal.<ref>{{citation |last=Riehle |first=Dirk |title=Framework Design: A Role Modeling Approach |url=http://www.riehle.org/computer-science/research/dissertation/diss-a4.pdf |year=2000 |publisher=[[ETH Zurich|Swiss Federal Institute of Technology]] }}</ref> While useful, these tools are not required in order to doperform dependency injection.<ref>{{Cite web |title=Dependency Injection != using a DI container |url=http://www.loosecouplings.com/2011/01/dependency-injection-using-di-container.html |access-date=2015-07-18 |website=www.loosecouplings.com }}</ref><ref>{{Citecite web |title=Black Sheep » DIY-DI » Print |url=http://blacksheep.parry.org/archives/diy-di/print/ |url-status=dead |archive-url=https://web.archive.org/web/20150627215638/http://blacksheep.parry.org/archives/diy-di/print |archive-date=2015-06-27 |access-date=2015-07-18 |website=blacksheep.parry.org }}</ref>
 
Some frameworks, like [[Spring Framework|Spring]], can use external configuration files to plan program composition:
Line 209 ⟶ 224:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
 
public class Injector {
 
public static void main(final String[] args) {
// Details about which concrete service to use are stored in configuration separate from the program itself.
final BeanFactory beanfactory = new ClassPathXmlApplicationContext("Beans.xml");
final Client client = (Client) beanfactory.getBean("client");
System.out.println(client.greet());
}
Line 222 ⟶ 236:
</syntaxhighlight>
 
Even with a potentially long and complex object graph, the only class mentioned in code is the entry point, in this case <code>Client</code>.<code>Client</code> has not undergone any changes to work with Spring and remains a [[Plain Old Java Object|POJO]].<ref>{{Citecite web |title = Spring Tips: A POJO with annotations is not Plain |url = http://springtips.blogspot.com/2007/07/pojo-with-annotations-is-not-plain.html|access-date = 2015-07-18 |archive-url = https://web.archive.org/web/20150715045353/http://springtips.blogspot.com/2007/07/pojo-with-annotations-is-not-plain.html |archive-date = 2015-07-15 |url-status = dead }}</ref><ref>{{Citecite web |title = Annotations in POJO – a boon or a curse? {{!}} Techtracer |url = http://techtracer.com/2007/04/07/annotations-in-pojo-a-boon-or-a-curse/ |access-date = 2015-07-18 |date = 2007-04-07 }}</ref><ref>
{{cite book |url=https://books.google.com/books?id=FCVnsq1ZUI0C&q=spring+pojo+annotation+free&pg=PA64 |title=Pro Spring Dynamic Modules for OSGi Service Platforms |publisher=APress |access-date=2015-07-06 |isbn=9781430216124 |date=2009-02-17 }}
{{cite book
|url=https://books.google.com/books?id=FCVnsq1ZUI0C&q=spring+pojo+annotation+free&pg=PA64|title=Pro Spring Dynamic Modules for OSGi Service Platforms|publisher=APress |access-date=2015-07-06|isbn=9781430216124|date=2009-02-17}}
</ref> By keeping Spring-specific annotations and calls from spreading out among many classes, the system stays only loosely dependent on Spring.<ref name="sites.google.com" />
 
Line 282 ⟶ 295:
 
The <code>ng-controller</code> directive triggers the injector to create an instance of the controller and its dependencies.
 
=== C++ ===
This sample provides an example of constructor injection in [[C++]].
<syntaxhighlight lang="c++">
import std;
 
class DatabaseConnection {
public:
void connect() {
std::println("Connecting to database...");
}
};
 
class DatabaseService {
private:
DatabaseConnection& dbConn;
public:
explicit DatabaseService(DatabaseConnection& db):
dbConn{db} {}
 
void execute() {
dbConn.connect();
std::println("Executing database service...");
}
};
 
int main(int argc, char* argv[]) {
DatabaseConnection db;
DatabaseService sv(db);
sv.execute();
}
</syntaxhighlight>
 
This sample provides an example of interface injection in C++.
<syntaxhighlight lang="c++">
import std;
 
enum class DatabaseConnectionError {
NoConnection,
// more errors here
};
 
class IConnection {
public:
virtual void connect() = 0;
virtual ~IConnection() = default;
};
 
class DatabaseConnection: public IConnection {
public:
DatabaseConnection() = default;
 
void connect() override {
std::println("Connecting to database...");
}
};
 
class DatabaseService {
private:
std::shared_ptr<IConnection> conn;
public:
DatabaseService() = default;
 
void setConnection(std::shared_ptr<IConnection> nextConn) noexcept {
conn = nextConn;
}
 
std::expected<void, DatabaseConnectionError> execute() {
if (conn) {
conn->connect();
std::println("Executing database service...");
} else {
return std::unexpected(DatabaseConnectionError::NoConnection);
}
}
};
 
int main(int argc, char* argv[]) {
std::shared_ptr<DatabaseConnection> db = std::make_shared<DatabaseConnection>();
DatabaseService sv;
sv.setConnection(db);
sv.execute();
}
</syntaxhighlight>
 
=== C# ===
This sample provides an example of constructor injection in [[C#C# (programming language)|C#]].
<syntaxhighlight lang="csharp">
using System;
Line 291 ⟶ 389:
 
// Our client will only know about this interface, not which specific gamepad it is using.
interface IGamepadFunctionalityIGamePadFunctionality {
{
string GetGamepadName();
string GetGamePadName();
void SetVibrationPower(float InPower);
void SetVibrationPower(float power);
}
 
// The following services provide concrete implementations of the above interface.
 
class XBoxGamepadXboxGamePad : IGamepadFunctionalityIGamePadFunctionality {
{
float VibrationPower = 1.0f;
float vibrationPower = 1.0f;
public string GetGamepadNameGetGamePadName() => "Xbox controller";
public void SetVibrationPower(float InPowerpower) => VibrationPowerthis.vibrationPower = Math.Clamp(InPowerpower, 0.0f, 1.0f);
}
 
class PlayStationJoystick : IGamePadFunctionality
class PlaystationJoystick : IGamepadFunctionality {
{
float VibratingPower = 100.0f;
float vibratingPower = 100.0f;
public string GetGamepadNameGetGamePadName() => "PlayStation controller";
public void SetVibrationPower(float InPowerpower) => VibratingPowerthis.vibratingPower = Math.Clamp(InPowerpower * 100.0f, 0.0f, 100.0f);
}
 
class SteamController : IGamepadFunctionalityIGamePadFunctionality {
{
double Vibrating = 1.0;
double vibrating = 1.0;
public string GetGamepadNameGetGamePadName() => "Steam controller";
public void SetVibrationPower(float InPowerpower) => Vibratingthis.vibrating = Convert.ToDouble(Math.Clamp(InPowerpower, 0.0f, 1.0f));
}
 
// This class is the client which receives a service.
class Gamepad {GamePad
{
IGamepadFunctionality _GamepadFunctionality;
IGamePadFunctionality gamePadFunctionality;
 
// The service is injected through the constructor and stored in the above field.
public GamePad(IGamePadFunctionality gamePadFunctionality) => this.gamePadFunctionality = gamePadFunctionality;
public Gamepad(IGamepadFunctionality InGamepadFunctionality) => _GamepadFunctionality = InGamepadFunctionality;
 
public void Showcase() {
{
// The injected service is used.
string gamePadName = this.gamePadFunctionality.GetGamePadName();
var gamepadName = _GamepadFunctionality.GetGamepadName();
varstring message = $"We're using the {gamepadNamegamePadName} right now, do you want to change the vibrating power?";
Console.WriteLine(message);
}
Line 338 ⟶ 442:
 
class Program {
static void Main(string[] args) {
{
var steamController = new SteamController();
SteamController steamController = new SteamController();
// We could have also passed in an XboxController, PlaystationJoystickPlayStationJoystick, etc.
// The gamepad doesn't know what it's using and doesn't need to.
varGamePad gamepad = new GamepadGamePad(steamController);
gamepad.Showcase();
}
}
</syntaxhighlight>
 
=== Go ===
Go does not support classes and usually dependency injection is either abstracted by a dedicated library that utilizes [[Reflective programming|reflection]] or [[Generic programming|generics]] (the latter being supported since Go 1.18<ref>{{Cite web |title=Go 1.18 Release Notes - The Go Programming Language |url=https://go.dev/doc/go1.18 |access-date=2024-04-17 |website=go.dev |language=en}}</ref>).<ref>{{Cite web |date=April 17, 2024 |title=Awesome Go – dependency injection |url=https://github.com/avelino/awesome-go?tab=readme-ov-file#dependency-injection |access-date=April 17, 2024 |website=Github}}</ref> A simpler example without using dependency injection libraries is illustrated by the following example of an [[Model–view–controller|MVC]] web application.
 
First, pass the necessary dependencies to a router and then from the router to the controllers:
<syntaxhighlight lang="go">
package router
 
import (
"database/sql"
"net/http"
 
"example/controllers/users"
 
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
 
"github.com/redis/go-redis/v9"
"github.com/rs/zerolog"
)
 
type RoutingHandler struct {
// passing the values by pointer further down the call stack
// means we won't create a new copy, saving memory
log *zerolog.Logger
db *sql.DB
cache *redis.Client
router chi.Router
}
 
// connection, logger and cache initialized usually in the main function
func NewRouter(
log *zerolog.Logger,
db *sql.DB,
cache *redis.Client,
) (r *RoutingHandler) {
rtr := chi.NewRouter()
 
return &RoutingHandler{
log: log,
db: db,
cache: cache,
router: rtr,
}
}
 
func (r *RoutingHandler) SetupUsersRoutes() {
uc := users.NewController(r.log, r.db, r.cache)
 
r.router.Get("/users/:name", func(w http.ResponseWriter, r *http.Request) {
uc.Get(w, r)
})
}
</syntaxhighlight>
 
Then, you can access the private fields of the [[Record (computer science)|struct]] in any method that is its [[Pointer (computer programming)|pointer]] receiver, without violating encapsulation.
<syntaxhighlight lang="go">
package users
 
import (
"database/sql"
"net/http"
 
"example/models"
 
"github.com/go-chi/chi/v5"
"github.com/redis/go-redis/v9"
"github.com/rs/zerolog"
)
 
type Controller struct {
log *zerolog.Logger
storage models.UserStorage
cache *redis.Client
}
 
func NewController(log *zerolog.Logger, db *sql.DB, cache *redis.Client) *Controller {
return &Controller{
log: log,
storage: models.NewUserStorage(db),
cache: cache,
}
}
 
func (uc *Controller) Get(w http.ResponseWriter, r *http.Request) {
// note that we can also wrap logging in a middleware, this is for demonstration purposes
uc.log.Info().Msg("Getting user")
 
userParam := chi.URLParam(r, "name")
 
var user *models.User
// get the user from the cache
err := uc.cache.Get(r.Context(), userParam).Scan(&user)
if err != nil {
uc.log.Error().Err(err).Msg("Error getting user from cache. Retrieving from SQL storage")
}
 
user, err = uc.storage.Get(r.Context(), "johndoe")
if err != nil {
uc.log.Error().Err(err).Msg("Error getting user from SQL storage")
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
}
</syntaxhighlight>
 
Finally you can use the database connection initialized in your main function at the data access layer:
<syntaxhighlight lang="go">
package models
 
import (
"database/sql"
"time"
)
 
type (
UserStorage struct {
conn *sql.DB
}
 
User struct {
Name string 'json:"name" db:"name,primarykey"'
JoinedAt time.Time 'json:"joined_at" db:"joined_at"'
Email string 'json:"email" db:"email"'
}
)
 
func NewUserStorage(conn *sql.DB) *UserStorage {
return &UserStorage{
conn: conn,
}
}
 
func (us *UserStorage) Get(name string) (user *User, err error) {
// assuming 'name' is a unique key
query := "SELECT * FROM users WHERE name = $1"
 
if err := us.conn.QueryRow(query, name).Scan(&user); err != nil {
return nil, err
}
 
return user, nil
}
</syntaxhighlight>
Line 354 ⟶ 603:
* [[Factory pattern]]
* [[Inversion of control]]
* [[Mock trainwreck]]
* [[Plug-in (computing)]]
* [[Strategy pattern]]
* [[AngularJS]]
* [[Service locator pattern]]
* [[Parameter (computer programming)]]
Line 362 ⟶ 611:
 
== References ==
{{Reflistreflist}}
 
== External links ==
Line 372 ⟶ 621:
* [http://martinfowler.com/articles/injection.html Martin Fowler's original article that introduced the term Dependency Injection]
* [http://martinfowler.com/eaaCatalog/plugin.html P of EAA: Plugin]
* {{usurped|1=[https://web.archive.org/web/20080313170630/http://www.javalobby.org/articles/di-heritage/ The Rich Engineering Heritage Behind Dependency Injection]}} - [[Andrew McVeigh]] - A detailed history of dependency injection.
* [http://tutorials.jenkov.com/dependency-injection/index.html What is Dependency Injection?] - An alternative explanation - Jakob Jenkov
* [http://www.developer.com/net/net/article.php/3636501 Writing More Testable Code with Dependency Injection -- Developer.com, October 2006] {{Webarchive|url=https://web.archive.org/web/20080311121626/http://www.developer.com/net/net/article.php/3636501 |date=2008-03-11 }}