Ich habe bereits eine Antwort auf das Open-Closed-Prinzip (OCP) und das Liskov-Substitutionsprinzip (LSP) geschrieben, und beide Prinzipien hängen viel miteinander zusammen, sind aber konzeptionell immer noch unterschiedlich, mit einigen erfundenen Beispielen dafür, dass man eins hat, aber nicht das andere. Aufgrund dieser Antwort werde ich nur kurz auf OCP eingehen und mich eingehender mit DIP und den Ursachen befassen.
Versuchen wir zu diskutieren, wie OCP mit dem Dependency Inversion Principle (DIP) zusammenhängt und sich unterscheidet, indem wir zuerst die verschiedenen Prinzipien erklären.
Prinzip der Abhängigkeitsinversion
Wenn Sie Onkel Bobs OOD-Prinzipien lesen, werden Sie feststellen, dass DIP Folgendes aussagt:
Hängen Sie von Abstraktionen ab, nicht von Konkretionen.
Eine Abstraktion in Java wird einfach mit interface
und abstract
Schlüsselwörtern erreicht, was bedeutet, dass Sie einen "Vertrag" für eine Software-Entität haben, der der Code folgen muss. Einige Programmiersprachen verfügen nicht über die Möglichkeit, Verhaltensweisen für den folgenden Code explizit festzulegen. Daher müssen Abstraktionen eher manuell befolgt werden, als dass der Compiler Sie bei der Durchsetzung des Vertrags unterstützt. In C ++ gibt es beispielsweise Klassen mit virtuellen Methoden, und in dynamischen Programmiersprachen wie Javascript müssen Sie sicherstellen, dass Sie Objekte auf die gleiche Weise verwenden (im Fall von Javascript wurde dies in TypeScript erweitert, um ein Typensystem hinzuzufügen, das Ihnen dabei hilft mit schriftlichen Verträgen, die vom Compiler überprüft werden).
Der Name beinhaltet den Begriff "Inversion", weil Sie traditionell (wie Sie im alten Zeitalter der Programmierung wussten) Softwarestrukturen geschrieben haben, die Module höherer Ebene abhängig von Modulen niedrigerer Ebene hatten. ZB machte es Sinn, ButtonAtKitchen
Handling-Eingaben für a KitchenLamp1
und zu haben KitchenLamp2
. Leider hat das die Software viel spezifischer gemacht, als es sein musste, und das Objektdiagramm würde so aussehen:
Wenn Sie also die Software allgemeiner gestalten, indem Sie "Verträge" hinzufügen. Beachten Sie, wie die Pfeile im Objektdiagramm die Richtung "umkehren". Diese Küchenlampen sind jetzt abhängig von a Button
. Mit anderen Worten, die Details hängen jetzt von Abstraktionen ab und nicht mehr umgekehrt.
Daher haben wir eine allgemeinere Definition von DIP, die auch im Originalartikel von DIP von Onkel Bob beschrieben ist .
A. High-Level-Module sollten nicht von Low-Level-Modulen abhängen. Beides sollte von der Abstraktion abhängen. B. Abstraktionen sollten nicht von Details abhängen. Details sollten von Abstraktionen abhängen.
Open-Closed-Prinzip
In Anlehnung an die Prinzipien von Onkel Bob werden Sie feststellen, dass OCP Folgendes feststellt:
Sie sollten in der Lage sein, das Verhalten einer Klasse zu erweitern, ohne es zu ändern.
Ein Beispiel dafür, dies zu erreichen ist es, die verwenden Strategie - Muster , wo eine Context
Klasse für Änderungen geschlossen (dh Sie können nicht ändern , es ist interner Code überhaupt) , ist aber auch offen für die Erweiterung durch es Abhängigkeiten (dh die Strategie Klassen) zusammenarbeiten.
Generell ist jedes Modul so aufgebaut, dass es durch seine Erweiterungspunkte erweiterbar ist.
OCP ist ähnlich wie DIP, oder?
Nein , nicht wirklich.
Obwohl beide über Abstraktionen diskutieren, sind sie konzeptionell unterschiedlich. Beide Prinzipien betrachten unterschiedliche Kontexte, OCP in einem bestimmten Modul und DIP in mehreren Modulen. Sie können beides gleichzeitig wie bei den meisten Gang-of-Four-Designmustern erreichen, aber Sie können sich trotzdem vom Weg entfernen.
In dem oben erwähnten DIP-Beispiel ist mit der Taste und den Küchenlampen keine der Küchenlampen erweiterbar (und es besteht derzeit keine Notwendigkeit, dies zu erläutern). Das Design bricht OCP, folgt aber DIP .
Ein umgekehrtes (und erfundenes) Beispiel wäre, dass eine Küchenlampe erweiterbar ist (wobei der Erweiterungspunkt so etwas wie a ist LampShade
), aber der Knopf immer noch von den Lampen abhängig ist . Es bricht DIP, folgt aber OCP .
Mach dir keine Sorgen, es passiert
Dies ist tatsächlich etwas, das im Produktionscode häufig vorkommt und das teilweise gegen ein Prinzip verstößt. In größeren Softwaresystemen (dh alles, was größer als die obigen Beispiele ist) können Sie ein Prinzip brechen, das andere jedoch normalerweise beibehalten, weil Sie den Code einfach halten müssen. Dies ist meines Erachtens in Ordnung für kleine und in sich geschlossene Module, da sie im Zusammenhang mit dem Single Responsibility Principle (SRP) stehen.
Sobald ein Modul kompliziert wird, müssen Sie es höchstwahrscheinlich unter Berücksichtigung aller Prinzipien betrachten und es neu entwerfen oder in ein bekanntes Muster umgestalten .