Dependency Injection

aus Wikipedia, der freien Enzyklopädie
Wechseln zu: Navigation, Suche

Als Dependency Injection (englisch dependency ‚Abhängigkeit‘, injection ‚Injektion‘) wird in der objektorientierten Programmierung ein Konzept und der Vorgang dazu genannt, bei dem zur Laufzeit die Abhängigkeiten eines Objekts diesem von einem anderen Objekt als Referenzen zur Verfügung gestellt werden.

Als Grundsatz für die Umsetzung von Dependency Injection gilt es also in einem Objekt keine Abhängigkeiten von anderen Objekten und Methoden zu besitzen, welche nicht über den Konstruktor oder eine Methode übergeben wurden. Statische Methoden werden dabei über einen Adapter angesprochen, um Modultests zu ermöglichen.

Inhaltsverzeichnis

Wortbedeutung [Bearbeiten]

Die Bezeichnung Dependency Injection wurde 2004 von Martin Fowler eingeführt, um den damaligen Begriff Inversion of Control zu präzisieren: „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)[1]

Hintergründe [Bearbeiten]

Mit Dependency Injection ist es möglich - entsprechend dem Single-Responsibility-Prinzip - die Verantwortlichkeit für den Aufbau des Abhängigkeitsnetzes zwischen den Objekten eines Programmes aus den einzelnen Klassen in eine zentrale Komponente zu überführen.

In einem klassisch aufgebauten OO-System ist jedes Objekt selbst dafür zuständig, seine Abhängigkeiten, also benötigte Objekte und Ressourcen, zu erzeugen und zu verwalten. Dafür muss jedes Objekt einige Kenntnisse seiner Umgebung mitbringen, die es zur Erfüllung seiner eigentlichen Aufgabe normalerweise nicht benötigen würde.

Dependency Injection überträgt die Verantwortung für das Erzeugen und die Verknüpfung von Objekten an eine eigenständige Komponente, wie beispielsweise ein extern konfigurierbares Framework. Dadurch wird der Code des Objektes unabhängig von seiner Umgebung. Das vermeidet unnötige Abhängigkeiten beim Kompilieren und erleichtert besonders die Erstellung von Unit-Tests.

Nachteilig kann sich hingegen je nach verwendetem DI-Framework auswirken, dass Programmlogik in Konfigurationsdateien ausgelagert werden muss, was die Übersichtlichkeit vermindern und die Wartung erschweren kann: die Entwickler müssen nun zum Verstehen des Codes noch die Konfiguration berücksichtigen, welche sich zudem manchen Hilfsmitteln der Codeanalyse (z. B. IDE-unterstütztes Finden von Abhängigkeiten oder Refactoring) entzieht.

Umsetzung [Bearbeiten]

Martin Fowler beschreibt drei verschiedene Arten zum Setzen benötigter Referenzen, die er mit dem Begriff Dependency Injection verbindet: Interface Injection, Setter Injection und Constructor Injection. (Abschnitt „Forms of Dependency Injection“ in [1]) Alle von ihm geschilderten Verfahrensweisen verwenden dabei Methodenaufrufe, bei denen die zu setzenden Abhängigkeiten nicht Rückgabewert sondern Parameter sind.

Interface Injection [Bearbeiten]

Das Modul der injizierenden Klasse definiert ein Interface, das von abhängigen Klassen implementiert werden muss, um zur Laufzeit die Abhängigkeiten zur Verfügung gestellt zu bekommen.

interface Injizierbar {
  void injiziere(Abhängigkeit abhängigkeit);
}
 
class Abhängiges implements Injizierbar {
  private Abhängigkeit abhängigkeit;
 
  public void injiziere(Abhängigkeit abhängigkeit)  {
    this.abhängigkeit = abhängigkeit;
  }
}
 
class Injizierer {
  void methode() {
    Injizierbar injizierbares = ... ;
    Abhängigkeit abhängigkeit = ... ;
    injizierbares.injiziere(abhängigkeit);
  }
}

Setter Injection [Bearbeiten]

Die abhängige Klasse stellt Methoden zur Verfügung, die dazu verwendet werden, die Abhängigkeiten zur Verfügung zu stellen.

interface IAbhängiges {
  void setAbhängigkeit(Abhängigkeit abhängigkeit);
}
 
class Abhängiges implements IAbhängiges {
  private Abhängigkeit abhängigkeit;
 
  public void setAbhängigkeit(Abhängigkeit abhängigkeit) {
    this.abhängigkeit = abhängigkeit;
  }
}
 
class Injizierer {
  void methode() {
    IAbhängiges abhängiges = ... ;
    Abhängigkeit abhängigkeit = ... ;
    abhängiges.setAbhängigkeit(abhängigkeit);
  }
}

Constructor Injection [Bearbeiten]

Abhängigkeiten von anderen Klassen werden über Konstruktoren zur Verfügung gestellt. PicoContainer ist eines der Frameworks, die diese Art umsetzen.

interface IAbhängiges {
  public Abhängiges(Abhängigkeit parameter);
}
 
class Abhängiges implements IAbhängiges {
  private Abhängigkeit abhängigkeit;
 
  public Abhängiges(Abhängigkeit abhängigkeit)  {
    this.abhängigkeit = abhängigkeit;
  }
}
 
class Injizierer {
  void methode() {      
    Abhängigkeit abhängigkeit = ... ;
    IAbhängiges abhängiges = new Abhängiges(abhängigkeit) ;
  }
}

Weitere Möglichkeiten [Bearbeiten]

Es ist auch möglich, Dependency Injection auf andere Art und Weise umzusetzen,[2] wie sie in manchen Frameworks Verwendung finden. Beispielsweise können Abhängigkeiten, nach Möglichkeiten der Programmiersprache, durch Reflexion oder durch direktes Setzen des Verweises darauf in den Speicher, auch ohne Methodenaufrufe gesetzt werden.

Dependency Injection ist ein Konzept, das ähnlich dem Entwurfsmuster Abstrakte Fabrik selbst implementiert werden kann. Es existieren jedoch verschiedene Frameworks für diverse Programmiersprachen und Plattformen zur Umsetzung die fertige Lösungen zur Verfügung stellen. Diese implementieren das Muster mit zum Teil umfassender, weiterführender Funktionalität, wie beispielsweise das Einlesen der Konfiguration aus Dateien und deren Prüfung auf formale Korrektheit. Siehe dazu die Liste von Dependency Injection Frameworks.

Weblinks [Bearbeiten]

Einzelnachweise [Bearbeiten]

  1. a b Martin Fowler: Inversion of Control Containers and the Dependency Injection pattern. 23. Januar 2004. In englischer Sprache. Abgerufen am 16. Mai 2013.
  2. Ben Yu: Dependency Injection Types. In englischer Sprache. Abgerufen am 16. Mai 2013.