Introduction

With dependency injection, a class no longer has to manage its dependencies itself, as they are automatically provided. This is intended to make it easier to change dependencies, as they will have fewer adjustments to their dependencies, and ideally no adjustments at all.

Using dependency injection, the dependency can be injected a three points in a class. It is possible to introduce the dependency when constructing the client, where the dependency is introduced in the constructor. A second possibility is to introduce the dependency using a setter method, which is called after the constructor. The last possibility is to introduce the dependency directly in the field, so that neither a constructor nor a specific setter method is needed.

Dependency injection is an extension of the Dependency Inversion under the SOLID principle, which brings the dependency from bottom to top.

Roles

To implement dependency injection four roles are needed. These will be explained in the following sections.

Service

The service is the part of the application that should be used elsewhere, as it implements part of the required business logic. To keep the application as modular as possible and in line with the Dependency Inversion Principle, a service is never used directly in a client. Instead, a service implements an interface that can be used by clients.

Client

The client refers to the part of the application that should consume and use a service. The dependency should be “injected” here. This allows the client to easily use the functionalities of the interface implemented by the service without having to worry about which implementation it is using.

Interface

The interface is the abstraction between client and service. It defines an contract that tells a client which methods are available on a service and makes it clear to a service which methods need to be implemented.

Injector

The task of the injector is to “inject” the respective services into the clients using the different interfaces, so that they can use them. In comparison to the Dependency Inversion, the injector is the only new role that was not needed before.

CDI

Contexts and Dependency Injection (CDI) is a Java standard that extends the principle of dependency injection. CDI allows the dependencies of the different modules to be automatically injected, eliminating the need to manually pass the required dependencies. CDI decides based on different contexts and a configuration which dependency is needed where.

Sources

Wikipedia - Prinzipien objektorientierten Designs
Wikipedia - Contexts and Dependency Injection
Stackify - Dependency Injection
Stackify - Dependency Inversion Principle

Example

To illustrate this principle, here is a small example in Java. Here we want to create an application that can be used to brew coffee with different coffee machines.

Starting Point

For the starters there are two coffee machines, the BasicCoffeeMachine Both machines have a method to brew coffee, but the PremiumCoffeeMachine can also brew espresso next to the filter coffee.

Abstraction

The first step to Dependency Injection is the abstraction of the public methods. To do this, an interface for the coffee machine must be created. Since not every Coffee machine can brew espresso there are two interfaces here, a basic one for all Coffee machines, which can brew filter coffee and a second one for the premium coffee machine, which can also brew espresso. The BasicCoffeeMachine can then implement the simple interface and the PremiumCoffeeMachine implements both.

Refactoring

Application

Now that both classes implement their interfaces, the coffee application can be created using the Dependency Injection principle. The application no longer has to manage which coffee machine it needs, but can simply request the interfaces it needs via its constructor. This allows the correct coffee machine to be injected when creating the coffee application.

Last updated 27 Nov 2024, 15:01 +0100 . history