{"id":372,"date":"2015-05-10T10:39:43","date_gmt":"2015-05-10T08:39:43","guid":{"rendered":"http:\/\/invidit.de\/blog\/?p=372"},"modified":"2015-07-04T14:37:27","modified_gmt":"2015-07-04T12:37:27","slug":"dependency-inversion-principle","status":"publish","type":"post","link":"https:\/\/invidit.de\/blog\/dependency-inversion-principle\/","title":{"rendered":"Dependency Inversion Principle"},"content":{"rendered":"<p>Hallo Spa\u00df-Coder.<\/p>\n<p>Zum Abschluss unserer Prinzipien-Reihe steht nun nicht mehr direkt ein Problem in einer Klasse im Zentrum, sondern vielmehr die Frage, wie sich Abh\u00e4ngigkeiten zwischen Klassen unterschiedlicher Ebenen verhalten. Wie also k\u00f6nnen wir darauf achten, dass unser System auch dann sauber bleibt, wenn es gro\u00df wird?<\/p>\n<p>Hier hilft uns das Letzte Prinzip aus der Liste der SOLI<strong>D<\/strong>-Prinzipien.<\/p>\n<p>&nbsp;<\/p>\n<h2>Dependency-Inversion-Prinzip (DIP)<\/h2>\n<blockquote><p>\u201eModule h\u00f6herer Ebenen sollten nicht von Modulen niedrigerer Ebenen abh\u00e4ngen.<br \/>\nBeide sollten von Abstraktionen abh\u00e4ngen.<\/p>\n<p>Abstraktionen sollten nicht von Details abh\u00e4ngen.<br \/>\nDetails sollten von Abstraktionen abh\u00e4ngen.\u201c<\/p>\n<p>&#8212; Dependency-Inversion-Prinzip (Quelle: <a href=\"http:\/\/de.wikipedia.org\/wiki\/Dependency-Inversion-Prinzip\">Wikipedia<\/a>)<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<h2>Erl\u00e4uterung des Prinzips<\/h2>\n<p><a href=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_Abh\u00e4ngikeitKlassen.png\"><img decoding=\"async\" loading=\"lazy\" class=\"  wp-image-379 alignright\" src=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_Abh\u00e4ngikeitKlassen.png\" alt=\"DIP_Abh\u00e4ngikeitKlassen\" width=\"230\" height=\"167\" srcset=\"https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_Abh\u00e4ngikeitKlassen.png 655w, https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_Abh\u00e4ngikeitKlassen-300x218.png 300w\" sizes=\"(max-width: 230px) 100vw, 230px\" \/><\/a>Annahme: wir haben zwei Klassen in unterschiedlichen Paketen bzw. Namensr\u00e4umen, von denen eine Klasse die andere Klasse kennt. Damit besteht zwischen den beiden Paketen eine Abh\u00e4ngigkeit. Ja und? Was ist das Problem? Mit einer starken Kopplung zwischen Paketen und generell zwischen Klassen nimmt die Austauschbarkeit ab. Nehmen wir als Beispiel einen CRUD-Service, der an eine bestimmte Implementierung einer Datenbankschicht gekoppelt ist. Was passiert, wenn die Datenbank gewechselt werden soll? Die Abh\u00e4ngigkeiten sind durch \u00c4nderung des Programmcodes aufzul\u00f6sen, bevor eine neue Implementierung der Datenbankschicht angebunden werden kann. Was kann ich machen, um die Kopplung besser &#8211; also lose &#8211; zu gestalten?<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_Abh\u00e4ngikeitMitInterface.png\"><img decoding=\"async\" loading=\"lazy\" class=\"  wp-image-376 alignleft\" src=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_Abh\u00e4ngikeitMitInterface.png\" alt=\"DIP_Abh\u00e4ngikeitMitInterface\" width=\"308\" height=\"148\" srcset=\"https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_Abh\u00e4ngikeitMitInterface.png 964w, https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_Abh\u00e4ngikeitMitInterface-300x144.png 300w, https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_Abh\u00e4ngikeitMitInterface-960x464.png 960w\" sizes=\"(max-width: 308px) 100vw, 308px\" \/><\/a> Um Kopplungen durch Implementierungen auszul\u00f6sen, k\u00f6nnen Schnittstellen eingef\u00fchrt werden. Was f\u00fcr unser Beispiel dann wie links stehend aussehen k\u00f6nnte. Dabei zeigt das gr\u00fcne Rechteck eine Schnittstelle (Interface), welche von der orangefarbene Klasse verwendet und von der blauen Klasse implementiert wird. Befinden sich orangefarbene Klasse und Schnittstelle in einem Paket, kann das drunter liegende Paket ausgetauscht werden, ohne in dem Paket dar\u00fcber eine \u00c4nderung vornehmen zu m\u00fcssen. Das neue Paket bringt einfach eine neue Implementierung der Schnittstelle mit.<\/p>\n<p>In diesem Fall haben wir die Abh\u00e4ngigkeit umgedreht: bisher vom oberen Paket zum unteren, jetzt vom unteren Paket zum oberen.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_CP.png\"><img decoding=\"async\" loading=\"lazy\" class=\"  wp-image-377 alignright\" src=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_CP.png\" alt=\"DIP_CP\" width=\"348\" height=\"224\" srcset=\"https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_CP.png 855w, https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_CP-300x193.png 300w\" sizes=\"(max-width: 348px) 100vw, 348px\" \/><\/a> Weiterhin k\u00f6nnen durch direkte Verwendung von Implementierungen, also Klassen, zirkul\u00e4re Abh\u00e4ngigkeiten entstehen, wie nebenstehende Grafik veranschaulicht. Diese Kreisabh\u00e4ngigkeiten kann der Compiler \u00fcblicherweise aufl\u00f6sen. Wenn allerdings ein Build-Server im Einsatz ist, kann dies bereits zum Problem f\u00fchren. Dadurch, dass sich ein verwendetes Paket \/ Klasse \u00e4ndert, muss das gerade betrachtete Paket \/ Klasse erneut erstellt werden, davon gibt es wieder eine Abh\u00e4ngigkeit, die erstellt werden muss &#8211; womit sich das System im Kreis dreht. Auch im Fall, dass die Implementierung angepasst werden muss, kann sich die \u00c4nderung durch alle Pakete \/ Klassen durchziehen. Wo fange ich an, wo h\u00f6re ich auf?<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_CPUnterbrochen.png\"><img decoding=\"async\" loading=\"lazy\" class=\"  wp-image-378 alignleft\" src=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_CPUnterbrochen.png\" alt=\"DIP_CPUnterbrochen\" width=\"320\" height=\"240\" srcset=\"https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_CPUnterbrochen.png 858w, https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/DIP_CPUnterbrochen-300x225.png 300w\" sizes=\"(max-width: 320px) 100vw, 320px\" \/><\/a>Wie links gezeigt, lassen sich zirkul\u00e4re Abh\u00e4ngigkeiten auch durch das Einziehen von Schnittstellen aufbrechen. Der rote Pfeil im Bild deutet an, dass hier die Richtung der Abh\u00e4ngigkeit gedreht wurde. Damit ist die Kreisabh\u00e4ngigkeit unterbrochen.<\/p>\n<p>Grunds\u00e4tzlich ist das DIP nicht mit dependecy injection &#8211; also dem injizieren von Abh\u00e4ngigkeiten zu verwechseln. Ein inversion of control (IoC) Framgework wie z.B. Spring \u00fcbernimmt dabei die Aufgabe, anhand der verwendeten Schnittstellen konkrete Implementierungen bereitzustellen. Grundvoraussetzung daf\u00fcr ist, dass die Abh\u00e4ngigkeiten durch Schnittstellen bereits aufgel\u00f6st wurden.<\/p>\n<p>Grunds\u00e4tzlich haben wir mindestens im <a href=\"http:\/\/invidit.de\/blog\/offen-und-geschlossen\/\" target=\"_blank\">Open Closed Principle<\/a> die lose Kopplung durch Schnittstellen besprochen.<\/p>\n<p>&nbsp;<\/p>\n<p>Weiterhin erreichen wird mit dem DIP:<\/p>\n<ul>\n<li>Unabh\u00e4ngigkeit zwischen Klassen und Modulen<\/li>\n<li>Ver\u00e4nderbarkeit und Austauschbarkeit<\/li>\n<li>Wiederverwendbarkeit<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h2>Unsere Erfahrung mit dem DIP<\/h2>\n<p>In einigen unserer Projekte haben wir ein IoC Framework verwendet (z.B. <a href=\"http:\/\/www.ninject.org\/\" target=\"_blank\">Ninject<\/a>) und daher grunds\u00e4tzlich mit Schnittstellen gearbeitet. Aber auch ohne Framework hat es sich als vorteilhaft erweisen, anstelle gegen eine Klasse, besser gegen eine Schnittstelle zu programmieren. Die Flexibilit\u00e4t ist deutlich h\u00f6her. Zus\u00e4tzlich hat sicherlich jeder mit Erfahrung in Unit Tests h\u00e4ufig festgestellt, dass sich Code mit Schnittstelle leichter testen l\u00e4sst. Mocks und Stubs k\u00f6nnen einfacher eingef\u00fchrt, die zu testende Implementierung leichter isoliert werden.<\/p>\n<p><a href=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/Battlez-Server-Architecture.png\"><img decoding=\"async\" loading=\"lazy\" class=\" size-medium wp-image-390 alignright\" src=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/Battlez-Server-Architecture-250x300.png\" alt=\"Battlez Server Architecture\" width=\"250\" height=\"300\" srcset=\"https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/Battlez-Server-Architecture-250x300.png 250w, https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/05\/Battlez-Server-Architecture.png 643w\" sizes=\"(max-width: 250px) 100vw, 250px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Im Projekt Battlez haben wir eine \u00fcbliche 3-Schichten Architektur verwendet (hier Netzwerk, Logik und UI, siehe Bild rechts) womit die verwendeten Bibliotheken f\u00fcr die Netzwerk-Kommunikation (wir nutzen <a href=\"https:\/\/code.google.com\/p\/lidgren-network-gen3\/\">LidgrenNetwork <\/a>in einem eigenen Wrapper) sehr leicht auszutauschen sind &#8211; gekoppelt ist diese \u00fcber nur zwei Schnittstellen.<\/p>\n<p>Einen Hinweis m\u00f6chte ich an dieser Stelle wiederholen: je mehr Komponenten ein Projekt enth\u00e4lt (sch\u00f6n klein, entkoppelt und wiederverwendbar), desto wichtiger wird die Projektstruktur sowie die Namensgebung. Aussagekr\u00e4fte Namen (siehe auch <a href=\"http:\/\/invidit.de\/blog\/basics-namen\/\">Aussagekr\u00e4ftige Namen<\/a>) unterst\u00fctzen dabei, den gesuchten Code schnell wiederzufinden.<\/p>\n<p>&nbsp;<\/p>\n<h2>Zusammenfassung<\/h2>\n<p>Mit dem letzten Design Prinzip der SOLID-Prinzipien schlie\u00dfen wird diese Reihe ab. Das DIP unterst\u00fctzt zus\u00e4tzlich zu den bisherigen Prinzipien die Entkopplung von Komponenten und damit die Ver\u00e4nder- und Wiederverwendbarkeit. Die SOLID-Prinzipien sind in der genannten Reihenfolge anzuwenden und werden in konsequenter Anwendung den Programmcode positiv beeinflussen.<\/p>\n<p>&nbsp;<\/p>\n<p>Viel Spa\u00df beim Anwenden.<\/p>\n<p>Eure Spa\u00df-Coder.<br \/>\nDieser Artikel basiert neben unseren Erfahrungen auf verschiedenen Internetquellen.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hallo Spa\u00df-Coder. Zum Abschluss unserer Prinzipien-Reihe steht nun nicht mehr direkt ein Problem in einer Klasse im Zentrum, sondern vielmehr die Frage, wie sich Abh\u00e4ngigkeiten zwischen Klassen unterschiedlicher Ebenen verhalten. Wie also k\u00f6nnen wir darauf achten, dass unser System auch dann sauber bleibt, wenn es gro\u00df wird? Hier hilft uns das Letzte Prinzip aus der [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":376,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[90],"tags":[60,61,17,19,59,44],"_links":{"self":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/372"}],"collection":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/comments?post=372"}],"version-history":[{"count":12,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/372\/revisions"}],"predecessor-version":[{"id":389,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/372\/revisions\/389"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media\/376"}],"wp:attachment":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media?parent=372"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/categories?post=372"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/tags?post=372"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}