Kolumne: Quality Time

Von der Abhängigkeit: Das „Dependency Inversion Principle“
Kommentare

Mit dem Buchstaben D erreichen wir die letzte Folge der aktuellen Serie über die SOLID-Prinzipien [1] nach Robert C. Martin. Falls Sie die ersten Teile der Serie zu diesen essenziellen Regeln des objektorientierten Softwaredesigns verpasst haben: Kein Problem, wir halten die Artikel unter [2] bis [5] zum Nachlesen für Sie bereit.

PHP Magazin

Die Kolumne „Von der Abhängigkeit“ von Tobias Schlitt ist erstmalig erschienen im PHP Magazin 2.2013

Das „Dependency Inversion Principle“ (D) beschreibt eine der wichtigsten Grundlagen der objektorientierten Anwendungsentwicklung: das Verstecken von Komplexität hinter der Fassade von Abstraktionen. Der Text des Prinzips gliedert sich in zwei Teile, die grob umrissen Folgendes besagen: a) Module auf höheren Ebenen sollten keine Abhängigkeiten auf Module niedrigerer Ebenen haben, sondern beide sollten von Abstraktionen abhängen. b) Abstraktionen sollten nicht von Implementierungsdetails abhängen, sondern die Details von der Abstraktion.

Wie so oft hilft ein praktisches Beispiel, um diesen theoretischen Zusammenhang besser zu erläutern (Listing 1).

Listing 1

Die kleine NewsLoader-Klasse verwendet einen News-Service um Nachrichten zu laden (fetchNews()) und einen Logger. So weit, so schön, so einfach. Problematisch ist allerdings, dass die Klasse nicht von abstrakten Konzepten abhängt, sondern von konkreten Implementierungen: Statt eine abstrakte NewsService-Klasse zu verlangen, wird die konkrete Realisierung auf Basis einer Google-Schnittstelle benötigt. Beim Logger sieht die Situation anders, aber nicht weniger schlimm aus. Zwar wird hier augenscheinlich eine Instanz von einem abstrakten Konzept Logger erwartet. Sehen Sie sich aber die zweite der gezeigten Codezeilen, in denen der Logger verwendet wird, an, ist das Problem zu erkennen: Der Aufruf der Methode writeToFile(), mit der scheinbar das letztendliche Schreiben der Log-Nachrichten auf die Festplatte angestoßen wird, spiegelt ganz klar ein Detail der Datei-Logger-Implementierung wider und gehört nicht zum abstrakten Konzept Logger. Dies wird insbesondere klar, wenn man sich alternative Implementierungen des Logger-Konzeptes vorstellt: Ein DatabaseLogger oder ein GraylogLogger werden bestimmt nicht „in eine Datei“ schreiben.

Es liegt also zum einen eine direkte Abhängigkeit auf ein Modul unterer Ebene vor (GoogleNewsService), zum anderen scheint die Abstraktion des Loggers von den Details einer FileLogger-Implementierung abzuhängen. Zwei Inkarnationen desselben Problems: fehlende oder falsche Abstraktion.

Die Auswirkungen solcher Abhängigkeiten auf Details wirken sich auf beiden Modulebenen aus: Zum einen wird das Austauschen des Loggers durch eine andere Implementierung erschwert – alle weiteren Implementierungen müssen sich an das vom FileLogger vorgeschriebene API halten, auch wenn sie die entsprechenden Methoden gar nicht benötigen oder, noch schlimmer, gar nicht bereitstellen können. Auf der anderen Seite muss bei jeder Verwendung des Loggers darauf geachtet werden, die entsprechende Methode zum eigentlichen Schreiben aufzurufen. Das macht die Verwendung des Loggers unnötig kompliziert und führt einen wichtigen Beweggrund hinter der Objektorientierung ad absurdum: Statt Komplexität hinter der Fassade von Objekten zu verstecken und die Verwendung auch komplizierter Funktionalitäten einfach darzustellen, werden unnötig Details an den Verwender weitergereicht.

Besser wäre im gezeigten Codebeispiel also gewesen, Abhängigkeiten auf abstrakte Konzepte (NewsService) zu bilden und die Details der eigentlichen Implementierungen hinter den verwendeten Abstraktionen (Logger) zu verstecken. Der Datei-Logger sollte als Konsequenz auch ohne den expliziten Aufruf von writeToFile() auskommen und dieses Implementierungsdetail hinter dem API des Logger-Konzeptes verstecken. Die konkreten Implementierungen eines Konzeptes – FileLogger und GoogleNewsService – hängen also, genauso wie ihre Verwender, von der entsprechenden Abstraktion ab.

Die Ähnlichkeit zwischen Dependency Inversion und dem in den letzten Jahren in der PHP-Welt allgegenwärtigen Dependency Injection ist übrigens keinesfalls zufällig: Das hier vorgestellte Prinzip bildet eine der Grundlagen zum sinnvollen Einsatz von Dependency Injection. Weiter spielen hier aber auch das „Single Responsibility Principle“, das „Liskov Substitution Principle“ und die restlichen SOLID-Prinzipien eine Rolle.

Tobias Schlitt ist Diplominformatiker (Uni) und arbeitet seit 1999 in professionellen Webprojekten auf Basis von PHP. Als Open-Source-Enthusiast beteiligt er sich an verschiedenen Communityprojekten. Tobias ist Mitgründer der Qafoo GmbH (http://qafoo.com), die Entwicklungsteams dabei unterstützt, hochqualitative Websoftware zu entwickeln. Dazu zählen unter anderem Consulting und Training zu Qualitätssicherungsprozessen und professionellem Software-Engineering.
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -