Start / Seminare / Angular für erfahrene Entwickler

Modul

Dependency Injection

Modul 7 von 22 aus dem Seminar Angular für erfahrene Entwickler

5 Kapitel in diesem Modul-Video · Laufzeit

Für Teams

Die Videos zeigen, wie es geht. Die Schulung sorgt dafür, dass Ihr Team es danach tut.

Ein Video kann niemanden fragen, warum es ausgerechnet in Ihrem Repository nicht funktioniert. Es kann kein Team auf eine gemeinsame Konvention bringen. Und es setzt sich niemand freiwillig drei Tage hin. In der Schulung sind am Ende alle auf demselben Stand, gearbeitet wurde am eigenen Code, und die offenen Fragen sind entschieden — in ein paar Tagen statt irgendwann nebenbei.

Vorgespräch am Telefon · Programm nach Maß · ab 1 Tag (8 Unterrichtseinheiten) · Teilnahmezertifikat

Schulung anfragen So läuft eine Schulung ab

Vertonung mit synthetischer Stimme · Inhalte redaktionell verantwortet · © 2026 HECKER CONSULTING, alle Rechte vorbehalten

Transkript

Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.

Dependency Injection

0:00 Dependency Injection ist in vielen Frameworks ein Muster, für das man sich entscheiden kann. In Angular ist sie die Verdrahtung, auf der alles andere läuft — der Router, der Datenzugriff, die Formulare, alles kommt darüber. Deshalb lohnt es sich, sie zu verstehen, auch wenn man sie selten direkt anfasst. Die Idee dahinter ist bekannt: Eine Klasse sagt, was sie braucht, statt es selbst zu beschaffen.

0:23 Das Interessante sind die Folgen — vor allem für Testbarkeit und für die Frage, was sich austauschen lässt.

Reaktivität und Anwendungsstruktur

0:30 Wir sind in der zweiten Hälfte des zweiten Tages. Vormittags ging es um Zustand und Änderungen, jetzt um Struktur. Dieses Modul klärt die Verdrahtung, das nächste die Zuständigkeiten. Beides zusammen entscheidet darüber, ob eine Anwendung in zwei Jahren noch änderbar ist.

Abhängigkeiten mit inject() beziehen

0:48 Beginnen wir bei der Schreibweise. Die hat sich geändert, und zwar zum Besseren — auch wenn der Unterschied zuerst nach Geschmack aussieht. Eine Abhängigkeit holen Sie heute über eine Funktion, nicht über einen Konstruktorparameter. Erlaubt ist das an genau definierten Stellen: bei der Feldinitialisierung, im Konstruktorrumpf, in Guards, Resolvern, Interceptors und Fabrikfunktionen.

1:10 Der Style Guide empfiehlt diese Form ausdrücklich. Dazu ein praktisches Detail: Ein Service wird mit einem eigenen Dekorator anwendungsweit bereitgestellt — das ist die Kurzschreibweise für die ausführliche Variante, die Sie aus älterem Code kennen. Denken Sie an ein Restaurant: Sie sagen, was Sie möchten, und es kommt fertig an den Tisch.

1:30 Hier sehen Sie beide Seiten. Oben der Service, der selbst wieder etwas bezieht — Abhängigkeiten sind also nicht auf Komponenten beschränkt. Unten die Komponente, die den Service holt. Worauf es ankommt: Die Abhängigkeit steht am Feld, also genau an der Stelle, an der sie benutzt wird. Man muss nicht zwischen Konstruktor und Verwendung hin- und herspringen.

1:52 Und weil es eine Funktion ist, ergibt sich der Typ aus dem Aufruf — Sie brauchen keine zusätzliche Typangabe und keinen Dekorator am Parameter. Vier Vorteile, und der dritte ist der, der die Entscheidung erzwingt: Funktionale Guards und Interceptors haben gar keinen Konstruktor. Wer mit ihnen arbeitet — und das werden Sie ab Modul neun —, braucht diese Form ohnehin. Die anderen drei sind angenehm: Der Typ ergibt sich aus dem Aufruf.

2:18 Vererbung wird einfacher, weil man den Konstruktor nicht durchreichen muss — wer jemals eine Basisklasse um eine Abhängigkeit erweitert hat, kennt den Schmerz. Und die Abhängigkeit steht dort, wo sie gebraucht wird. Der erste Punkt ist der, den jeder einmal macht: Die Funktion wird außerhalb des erlaubten Kontexts aufgerufen, etwa in einer normalen Methode.

2:40 Die Fehlermeldung ist zum Glück deutlich. Der zweite ist schleichender und deshalb gefährlicher: Eine Klasse zieht sich mehr Abhängigkeiten, als ihr Vertrag hergibt. Weil es so leicht ist, eine Zeile hinzuzufügen, wächst die Liste unbemerkt. Und der dritte ist ein Lesbarkeitsproblem: Alter und neuer Stil stehen in derselben Datei nebeneinander, und man fragt sich, ob das Absicht war.

Provider und Gültigkeitsbereiche

3:03 Jetzt zu der Entscheidung, die man tatsächlich treffen muss: Wo wird eine Abhängigkeit bereitgestellt? Denn davon hängt ab, wie lange sie lebt und wer sie teilt. Angular kennt zwei Ebenen. Die eine gilt für die ganze Anwendung, die andere hängt an Komponenten und Direktiven. Daraus ergeben sich drei praktische Orte: beim Start der Anwendung — dann gibt es eine gemeinsame Instanz für alle.

3:27 An einer Route — dann eine je Feature, die mit dem Feature entsteht und wieder verschwindet. Oder an einer Komponente — dann eine je Einbaustelle. Die Wahl ist keine Formalie. Sie entscheidet darüber, ob zwei Ansichten denselben Zustand sehen oder nicht. Lesen Sie die mittlere Spalte, die Lebensdauer — sie ist die eigentliche Information. Anwendungsweit heißt: lebt, solange die Anwendung läuft, und wird von allen geteilt.

3:54 An der Route: entsteht beim Betreten, verschwindet beim Verlassen. An der Komponente: eine je Einbaustelle, also drei Karten gleich drei Instanzen. In Spurweite steht der Datenzugriff anwendungsweit — eine Verbindung zur Schnittstelle genügt. Der Auftrags-Store steht dagegen an der Route, weil er zum Feature gehört und nicht zur Anwendung. Diese Unterscheidung werden wir im nächsten Modul begründen.

4:19 Vier Sätze, und die ersten beiden sind das Begriffspaar, um das es geht: geteilt oder getrennt. Anwendungsweit heißt geteilt — zwei Ansichten sehen denselben Zustand, was manchmal gewünscht ist und manchmal überrascht. Je Komponente heißt getrennt — zwei Karten stören einander nicht. Der dritte Punkt ist die Falle: Ein mehrfach bereitgestellter Dienst erzeugt mehrere Instanzen, ohne dass es auffällt. Sie ändern etwas in der einen und lesen aus der anderen.

4:47 Und der vierte ist die Faustregel: Was zusammengehört, gehört auf dieselbe Ebene. Der erste Punkt ist der häufigste Zuschnittsfehler: Ein Store steht anwendungsweit, obwohl er zu einem Feature gehört. Dann bleibt sein Zustand erhalten, wenn der Benutzer das Feature längst verlassen hat — und der Filter von vorgestern ist beim nächsten Aufruf noch gesetzt.

5:08 Der zweite ist der eben beschriebene doppelte Provider. Und der dritte ist der umgekehrte Fall: Zustand geht beim Verlassen der Route verloren, weil er dort bereitgestellt wurde — was richtig sein kann oder eben nicht. Wichtig ist, dass es eine Entscheidung war.

Injection Tokens und Konfiguration

5:23 Bleibt die Frage, wie man etwas bereitstellt, das keine Klasse ist. Und dabei stolpert man über eine Eigenheit von TypeScript, die man einmal verstanden haben muss. Ein Token stellt Werte bereit, die keine Klasse sind — Konfiguration, Funktionen, einfache Werte. Mit einer Fabrik versehen ist es baumschüttelbar und liefert gleich einen Standardwert mit.

5:45 Die Provider-Formen kennen Sie vermutlich: eine Klasse, ein fester Wert, eine Fabrik mit Abhängigkeiten, ein Alias, und die Variante für mehrere Beiträge zu einem Token. Und jetzt die Eigenheit: Ein TypeScript-Interface taugt nicht als Token. Es existiert zur Laufzeit nicht — es ist nur eine Zusage an den Compiler, kein Objekt, auf das man zeigen könnte.

6:07 Zwei Dinge sind hier bemerkenswert. Erstens die Fabrik: Sie liefert den Standard, und eine Umgebung überschreibt ihn beim Start mit einem festen Wert. Damit ist die Konfiguration immer vorhanden, auch im Test, ohne dass jemand sie bereitstellen muss. Zweitens die Typangabe am Token: Sie macht den Zugriff typsicher, obwohl der Wert ein einfaches Objekt ist. Worauf es ankommt: Konfiguration wird injiziert, nicht importiert.

6:32 Ein Import wäre kürzer und ließe sich im Test nicht austauschen — und genau darum geht es im nächsten Kapitel. Der erste Punkt ist der, den ich eben erklärt habe, und er kommt beim Einstieg zuverlässig: Ein Interface dient als Token und existiert zur Laufzeit nicht. Die Fehlermeldung ist zum Glück eindeutig. Der zweite ist der, der die Testbarkeit kostet: Konfiguration wird importiert statt injiziert.

6:56 Das funktioniert überall — außer dort, wo man sie ändern möchte. Und der dritte ist still: Die Option für mehrere Beiträge wird vergessen, der zweite Provider überschreibt den ersten, und der erste verschwindet ohne jede Warnung.

Austausch im Test und in Varianten

7:10 Damit zum eigentlichen Ertrag der ganzen Konstruktion. Denn Dependency Injection ist kein Selbstzweck — sie zahlt sich an einer bestimmten Stelle aus. Eine Abhängigkeit hinter einem Token lässt sich ersetzen, ohne die Aufrufer zu ändern. Das ist der ganze Punkt. Im Test stellen Sie eine andere Umsetzung bereit, und die Komponenten merken nichts davon. Dieselbe Technik trägt Varianten für Demo-, Test- und Produktivbetrieb.

7:36 Für Bibliotheken ist die übliche Form eine Funktion, die alle nötigen Provider bündelt — Sie kennen das von den Angular-eigenen Funktionen, die Router oder Datenzugriff einrichten. Der Aufrufer muss dann nicht wissen, was intern zusammengehört. Vier Zeilen, und darin steckt die gesamte Testbarkeit. Sie sagen: Wo jemand diesen Service anfordert, gib stattdessen diese Klasse.

7:59 Keine Komponente wird dafür geändert, kein Konstruktor angepasst, kein Schalter gesetzt. Worauf es ankommt: Damit das funktioniert, muss der Vertrag vorher klar sein — die Ersatzumsetzung muss dasselbe versprechen. Und genau hier zeigt sich, ob der Schnitt stimmt. Wenn sich eine Abhängigkeit schwer ersetzen lässt, liegt das selten am Test und meistens daran, dass der Vertrag zu viel oder zu wenig enthält.

8:24 Vier Punkte, und ich finde den ersten praktisch unterschätzt: Eine Demo-Umgebung mit festen Daten. Bei Falkenhorst gibt es Standorte mit schlechter Netzanbindung; eine Fassung, die ohne Schnittstelle läuft, ist dort keine Spielerei, sondern nützlich. Der zweite: Ein Ausfall lässt sich reproduzierbar nachstellen, statt darauf zu warten.

8:43 Der dritte macht die Architektur sichtbar — die Grenze zwischen Anwendung und Außenwelt wird zu einer Datei. Und der vierte ist der eigentliche Gewinn: Austauschbarkeit zwingt dazu, den Vertrag vorher zu klären. Der erste Punkt ist der häufigste Testfehler überhaupt: Der Test ersetzt die Umsetzung und prüft danach deren Interna. Dann testen Sie Ihre Fälschung, nicht Ihre Anwendung.

9:06 Der zweite ist subtiler und teurer: Die Fälschung weicht vom Vertrag ab — sie antwortet etwa immer sofort, wo die echte verzögert — und verdeckt damit einen echten Fehler. Und der dritte ist das Gegenteil von Sparsamkeit: Es wird alles austauschbar gemacht, auch was nie getauscht wird. Jede Abstraktion hat einen Preis, und der wird beim Lesen fällig.

Übung

9:27 Machen wir den Datenzugriff von Spurweite austauschbar. Das ist die Vorbereitung für fast alles, was in den nächsten Tagen kommt. Bisher rufen mehrere Komponenten von Spurweite direkt Daten ab — jede mit ihrer eigenen Adresse, jede mit ihrer eigenen Fehlerbehandlung. Das soll hinter eine Schnittstelle wandern, die sich für Test und Demo austauschen lässt, ohne dass eine Komponente davon etwas merkt.

9:50 Der letzte Halbsatz ist die eigentliche Anforderung. Wenn für den Austausch auch nur eine Komponente angefasst werden muss, ist der Schnitt nicht fertig. Das Lernziel ist knapp und präzise: eine Abhängigkeit so bereitstellen, dass sie ohne Änderung der Aufrufer ersetzbar ist. Das Erfolgskriterium macht daraus eine Probe: Der Test ersetzt sie vollständig, und keine Komponente musste dafür geändert werden.

10:15 Das lässt sich nachsehen — schauen Sie sich am Ende an, welche Dateien Sie angefasst haben. Wer früh fertig ist, ergänzt eine Funktion, die Token und Umsetzung gemeinsam bereitstellt. Das ist die Form, die Sie in jeder Angular-Bibliothek wiederfinden. Der zweite Schritt ist der, bei dem es interessant wird: den gemeinsamen Vertrag formulieren.

10:36 Und die Versuchung ist groß, dabei einfach die Schnittstelle nachzubauen — dieselben Endpunkte, dieselben Feldnamen. Tun Sie das nicht. Der Vertrag soll beschreiben, was die Anwendung braucht, nicht was die Schnittstelle anbietet. Danach ist der Rest mechanisch: Token anlegen, echte Umsetzung bereitstellen, im Test eine zweite registrieren.

10:56 Und der fünfte Schritt ist die Probe: nachsehen, ob wirklich keine Komponente geändert wurde. Der erste Punkt ist der, vor dem ich gerade gewarnt habe: Die Schnittstelle bildet die Fremdsystem-Schnittstelle ab statt den Bedarf der Anwendung. Dann ändert sich Ihr Vertrag, sobald das Fremdsystem sich ändert — und die Kapselung war umsonst.

11:16 Der zweite ist der halbe Umbau: Das Token wird angelegt, die Komponenten greifen aber weiter direkt zu. Und der dritte ist der, der im Test lange unbemerkt bleibt: Nur ein Teil wird ersetzt, der Rest ruft die echte Schnittstelle. Im nächsten Modul klären wir, wer eigentlich wofür zuständig ist.

Dieses Modul als Schulung für Ihr Team

Das Video zeigt den Stoff. In der Schulung arbeitet Ihr Team damit — an Ihrem eigenen Code, mit Übungen und mit den Fragen, die ein Video nicht beantwortet. Sie wählen die Module aus Angular für erfahrene Entwickler, wir bauen daraus ein Programm.

6 Tage·ab 900 EUR netto pro Tag (bis 3 Teilnehmende) ·Termin nach Vereinbarung

Als Team-Schulung anfragenWie eine Schulung abläuft →