Dependency injection

from Wikipedia, the free encyclopedia

In object-oriented programming, a design pattern that regulates the dependencies of an object at runtime is referred to as dependency injection ( DI , English dependency 'dependency' and injection 'injection', German  dependency injection or introduction of dependencies ) Another object, this dependency is stored in a central location - it is not generated by the initialized object itself.

Word meaning

The term Dependency Injection was introduced in 2004 by the software developer Martin Fowler to clarify the then term Inversion of Control : " Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various [Inversion of Control] advocates we settled on the name Dependency Injection. "( Martin Fowler : martinfowler.com)

backgrounds

With dependency injection it is possible - according to the single responsibility principle - to transfer responsibility for the construction of the dependency network between the objects of a program from the individual classes to a central component .

In a conventional system of object-oriented programming, on the other hand, each object is responsible for managing its dependencies, i.e. required objects and resources. To do this, every object has to have some knowledge of its environment that it would not normally need to carry out its actual task.

Dependency Injection transfers responsibility for creating and linking objects to an independent component, such as an externally configurable framework . This makes the object's code more independent of its environment. This can avoid dependencies on specific classes when compiling and, in particular, makes it easier to create unit tests .

advantages and disadvantages

advantages

  • The client has the flexibility to be configurable. Only the behavior of the client is fixed. The client can respond to anything that the intrinsic interface expected by the client supports.
  • A system's configuration details can be moved to configuration files so that the system can be reconfigured without recompiling. Separate configurations can be written for different situations that require different implementations of components. This includes, but is not limited to, tests.
  • Because no code behavior change is required, it can be used as a refactoring on legacy code. The result is clients that are more independent and easier to test in isolation by using stubs or dummy objects that simulate other objects that are not being tested. This simple check is often the first benefit seen using dependency injection.
  • The client can remove all knowledge of a specific implementation that it needs to use. This helps isolate the customer from the effects of design changes and errors. It promotes reusability, testability and maintainability.
  • Reduction of the boilerplate code in the application objects, since all work for initializing or setting up dependencies is carried out by a provider component.
  • Simultaneous or independent development. Two developers can independently develop classes that use each other while all they need to know is the interface through which the classes communicate. Often times, plug-ins are developed by third-party vendors who don't even speak to the developers who created the product that uses the plug-ins.
  • The coupling between a class and its dependency is reduced.

disadvantage

  • Clients are created whose configuration details must be provided by the design code. This can be a nuisance when there are obvious default settings available.
  • Reading code can be made difficult because it separates behavior from construction. This means that developers need to refer to more files to keep track of a system's performance.
  • Dependency injection frameworks are implemented with reflection or dynamic programming . This can hinder the use of IDE automation, e.g. B. Find References, View Call Hierarchy, and Secure Refactorings . The use of reflection can also affect the performance of the program.
  • Usually, more development effort is required in advance, as one cannot predict when and where it will be needed, but rather inquire that it will be injectedd, and then need to make sure it has been injected.
  • It takes effort to get out of classes and into the links between classes that may not always be desirable or easy to maintain.
  • Dependency on a dependency injection framework can be promoted.

structure

An example of a UML class diagram and sequence diagram for the Dependency Injection design pattern .

I.m UML class diagram instantiates the client class, for which ServiceA and ServiceB objects are required, not the ServiceA1 and ServiceB1 classes directly. Instead, an Injector class creates the objects and injects them into the client , which causes the client will be regardless of how the objects are created.

The UML sequence diagram shows the runtime interactions: The Injector - object creates the ServiceA1 and ServiceB1 objects . D.The injector then creates the client object and injects the ServiceA1 and ServiceB1 objects.

implementation

Martin Fowler describes three different ways of setting required references, which he associates with the term Dependency Injection: Constructor Injection , Interface Injection and Setter Injection (section Forms of Dependency Injection in). Use all procedures outlined by himmethod calls for which the dependencies to be set are not return values , see aboveChange parameters are.

Constructor injection

Dependencies on other classes are made available via constructors.

class Abhängiges {
  private Abhängigkeit abhängigkeit;

  //Konstruktor
  public Abhängiges(final Abhängigkeit abhängigkeit) {
    this.abhängigkeit = abhängigkeit;
  }
}

class Injizierer {
  void methode() {
    final Abhängigkeit abhängigkeit = ... ;
    final Abhängiges abhängiges = new Abhängiges(abhängigkeit);
  }
}

Interface injection

The module of the injecting class defines an interface that must be implemented by the dependent classes in order to have the dependencies made available at runtime.

interface IInjizierbar {
  void injiziere(final Abhängigkeit abhängigkeit);
}

class Abhängiges implements IInjizierbar {
  private final Abhängigkeit abhängigkeit;

  public void injiziere(final Abhängigkeit abhängigkeit) {
    this.abhängigkeit = abhängigkeit;
  }
}

class Injizierer {
  void methode() {
    final Abhängigkeit abhängigkeit = ... ;
    final IInjizierbar injizierbares = ... ;
    injizierbares.injiziere(abhängigkeit);
  }
}

Setter injection

The dependent class provides methods that are used to provide the dependencies.

class Abhängiges {
  private Abhängigkeit abhängigkeit;

  public void setAbhängigkeit(final Abhängigkeit abhängigkeit) {
    this.abhängigkeit = abhängigkeit;
  }
}

class Injizierer {
  void methode() {
    final Abhängiges abhängiges = ... ;
    final Abhängigkeit abhängigkeit = ... ;
    abhängiges.setAbhängigkeit(abhängigkeit);
  }
}

Further implementation options

It is also possible to implement dependency injection in other ways, as used in some frameworks. For example, depending on the possibilities of the programming language, dependencies can be set by reflection or by setting the reference to it directly in the memory, even without method calls.

There are various frameworks for various programming languages and platforms for implementation that provide ready-made solutions. These implement the pattern with partially comprehensive, advanced functionality, such as reading the configuration from files and checking it for formal correctness. See the list of Dependency Injection Frameworks .

Depending on the DI framework used, it can be disadvantageous that the program logic has to be outsourced to configuration files, which can reduce the clarity and make maintenance more difficult: the developers now have to take the configuration into account in order to understand the code, which is also used by some code analysis tools ( e.g. IDE- aided finding of dependencies or refactoring ).

This disadvantage can be avoided by implementing the dependency injection similar to the Abstract Factory design pattern without the use of a framework as part of the program itself. This type of implementation is called “Do-It-Yourself Dependency Injection”, or “DIY-DI” for short.

Individual evidence

  1. Dependency Injection in ASP.NET Core , Microsoft Docs
  2. ^ A b Martin Fowler: Inversion of Control Containers and the Dependency Injection pattern. January 23, 2004. In English . Retrieved May 16, 2013.
  3. ^ DZone: How Dependency Injection (DI) Works In Spring Java Application Development
  4. Ben Yu: Dependency Injection Types. ( Memento of the original from August 18, 2013 in the Internet Archive ) Info: The archive link was inserted automatically and has not yet been checked. Please check the original and archive link according to the instructions and then remove this notice. In English. Retrieved May 16, 2013. @1@ 2Template: Webachiv / IABot / yan.codehaus.org
  5. Chad Parry: DIY-TUE March 9, 2010. In English . Retrieved June 29, 2014.