Oğuzhan Açıkgöz Selbstständig

Dependency Injection bedeutet im weiteren Sinne, keine Verbindlichkeiten zwischen Klassen aufzubauen und alle benötigten Objekte als Parameter an die Klasse zu übergeben.

Vielfach gehört, recherchiert, gelesen und dennoch nicht verstanden: Dependency Injection. Ein mysteriöses Design Pattern mit sehr vielen Benefits, wie wir sehen werden. Nach diesem Artikel verstehen Sie Dependency Injection nicht nur, Sie werden von der Magie überwältigt sein und sie nicht mehr hergeben wollen.

Über Softwarearchitektur lässt sich meines Erachtens kein allgemeingültiger Konsens finden, nicht einmal in den kleinsten Entwicklergruppen und den flachsten Hierarchien. Die Begründung dafür ist einfach: Die einen sind sehr zielorientiert, lösen Probleme sehr konkret ohne generischen Ansatz; die anderen präferieren es, zu modellieren, auf Eventualitäten vorbereitet zu sein und eine Lösung möglichst mehrfach zu verwenden. Als Leser können Sie sich bestimmt auch in einer dieser beiden Kategorien wiederfinden. Ich fühle mich eher der letzteren Gruppe zugehörig und möchte mit dieser Artikelserie davon überzeugen, dass ein gut modelliertes Projekt schlicht langlebiger ist, weil geänderte Kundenwünsche einfacher in die Software inkludiert werden können. Im Zeitalter von „Agile“ – was fälschlicherweise sehr oft vom Auftraggeber als „Wir wollen das doch anders!“ interpretiert wird – ist es umso wichtiger, zu Beginn des Projekts die höchstrelevanten Pfeiler der Software richtig zu setzen.

Artikelserie

  • Teil 1: Dependency Injection in Aktion
  • Teil 2: Repository-Pattern-Kapselung der Datenschicht
  • Teil 3: Unit-of-Work-Pattern – schlanke Transaktionen an die Datenbank

Kluge Menschen aus den Anfängen der objektorientierten Entwicklung haben sich mit der Softwarearchitektur tief gehend beschäftigt und uns sehr nützliche Design Patterns beschert. Unter dem Akronym SOLID werden fünf wichtige Prinzipien zusammengefasst.

  1. Single-Responsibility-Prinzip: Eine Klasse sollte nicht mehr als eine Aufgabe besitzen. So oder so ähnlich wird das im Lehrbuch definiert. Im Gegensatz zur Definition ist die Bedeutung geradezu banal und offensichtlich. Eine Klasse Kunde hat typischerweise eine Methode KundeHinzufügen oder AddCustomer, mit der neue Kunden hinzugefügt werden können. Wenn wir annehmen, innerhalb der Methode einen Fehler abfangen zu können, also quasi eine try-catch-Anweisung implementieren, und im Fehlerfall eine Datei aus dem Dateisystem (per File.WriteAllText(..)) öffnen, um den Fehler zu hinterlegen, wird die Klasse Kunde mehr tun, als nur Kunden zu verwalten. Das Öffnen einer Datei ist semantisch inkorrekt und müsste offensichtlich in eine Log- oder Fileklasse ausgelagert werden. Ziel ist, falls sich beispielsweise der Dateipfad für die Logs ändert, nicht eine unbestimmte Zahl an Klassen zu haben, in der jeweils der Dateipfad geändert werden muss, sondern nur eine einzige Stelle – nämlich die Logging-Klasse.
  2. Open-Closed-Prinzip: Gemäß Lehrbuch bzw. Wikipedia heißt es: „Das Open-Closed-Prinzip besagt, dass Softwareeinheiten (hier Module, Klassen, Methoden usw.) Erweiterungen möglich machen sollen (dafür offen sein), aber ohne dabei ihr Verhalten zu ändern (ihr Sourcecode und ihre Schnittstelle sollte sich nicht ändern)“. Damit das verständlich wird, transferieren wird die obige Definition in ein Beispiel. Angenommen, wir entwickeln eine Autosimulationssoftware mit einer Hupe-Methode. Bei jedem Fahrzeug ertönt die Hupe etwas anders, sodass wir in die Hupe-Methode ein Switch-Case- bzw. If-Else-Statement einbauen, in dem die Automarke überprüft und der entsprechende Hupton erzeugt wird. Implizit würde diese Form der Implementierung bedeuten, dass bei jeder neu hinzugefügten Automarke eine Modifikation in der Hupe-Methode notwendig wird. Diese Modifikation ist gemäß der Definition nicht erwünscht, weil es keine Modularität bietet und offensichtlich fehleranfällig ist – dieser Teil ist der geschlossene „Closed“-Teil. Mit „offen für Erweiterungen“ ist der modulare Aufbau durch Vererbung gemeint. Anstelle einer Hupe-Methode, die für jedes Auto das Hupen übernimmt, wird eine Basisklasse oder ein Interface Auto mit der Methode Hupe definiert. Jede Automarke erbt von der Auto-Klasse und überschreibt die Hupe-Methode gemäß Anforderung. Der Vorteil ist nun, dass keine Modifikationen im bestehenden Code gemacht werden müssen, weil jedes neue Auto von der Basisklasse erbt und nach eigenen Wünschen die Hupe-Methode überschreibt. Mit diesem Verfahren ist der verantwortliche Softwarearchitekt vor Veränderungen weitestgehend geschützt.

Den vollständigen Artikel lesen Sie in der Ausgabe:

Windows Developer 4.18 - "Eine Frage der Architektur"

Alle Infos zum Heft
579830388Clean Code durch Design Patterns
X
- Gib Deinen Standort ein -
- or -