Open-Close-Prinzip (OCP) vs. Dependency-Inversion-Prinzip (DIP)

12

Ich habe versucht, den Unterschied zwischen dem Open Closed Principle (OCP) und dem Dependency Inversion Princible (DIP) zu verstehen .

Aufgrund meiner bisherigen Recherchen im Internet bin ich zu dem Schluss gekommen, dass DIP eine Option ist, mit der wir OCP erreichen können.

Ich bin ich richtig?

Können Sie mir ein Beispiel geben, das nicht DIP, sondern OCP folgt?

Jitendar
quelle

Antworten:

16

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 interfaceund abstractSchlü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, ButtonAtKitchenHandling-Eingaben für a KitchenLamp1und zu haben KitchenLamp2. Leider hat das die Software viel spezifischer gemacht, als es sein musste, und das Objektdiagramm würde so aussehen:

ButtonAtKitchen handhabt KitchenLamp1 und KitchenLamp2

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.

KitchenButton hat jetzt eine IButton-Abstraktion, von der die Küchenlampen abhängig sind

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 ContextKlasse 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.

Ein Modul mit Erweiterungspunkten

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 .

Spoike
quelle