Eines der OOP-Prinzipien, auf die ich gestoßen bin, ist: - Fassen Sie die Unterschiede zusammen.
Ich verstehe, was die wörtliche Bedeutung der Phrase ist, dh verstecke, was variiert. Ich weiß jedoch nicht, wie genau dies zu einem besseren Design beitragen würde. Kann es jemand anhand eines guten Beispiels erklären?
design
design-patterns
object-oriented
encapsulation
Haris Ghauri
quelle
quelle
I don't know how exactly would it contribute to a better design
Bei der Verkapselung von Details handelt es sich um eine lose Kopplung zwischen dem "Modell" und den Implementierungsdetails. Je weniger das "Modell" an die Implementierungsdetails gebunden ist, desto flexibler ist die Lösung. Und es macht es einfacher, es weiterzuentwickeln. "Entziehen Sie sich aus den Details".Antworten:
Sie können Code schreiben, der so aussieht:
Oder Sie können Code schreiben, der so aussieht:
Wenn das, was variiert, gekapselt ist, müssen Sie sich darüber keine Sorgen machen. Sie müssen sich nur Gedanken darüber machen, was Sie brauchen und was Sie verwenden.
Fassen Sie die Unterschiede zusammen, und Sie müssen keinen Code verteilen, der sich um die Unterschiede kümmert. Sie stellen das Haustier einfach auf einen bestimmten Typ ein, der zu sprechen weiß, und danach können Sie den Typ vergessen und es einfach wie ein Haustier behandeln. Sie müssen nicht nach dem Typ fragen.
Sie könnten denken, dass der Typ gekapselt ist, weil ein Getter für den Zugriff erforderlich ist. Ich nicht. Getter kapseln nicht wirklich. Sie klappern nur, wenn jemand Ihre Einkapselung bricht. Sie sind ein netter Dekorateur wie Aspekt-orientierter Haken, der am häufigsten als Debugging-Code verwendet wird. Egal wie Sie es schneiden, Sie belichten immer noch Typ.
Sie könnten sich dieses Beispiel ansehen und denken, ich verschmelze Polymorphismus und Verkapselung. Ich bin nicht. Ich verschmelze "was variiert" und "Details".
Die Tatsache, dass Ihr Haustier ein Hund ist, ist ein Detail. Eine, die für Sie variieren kann. Eines, das vielleicht nicht. Aber sicherlich eine, die von Person zu Person unterschiedlich sein kann. Sofern wir nicht glauben, dass diese Software nur von Hundeliebhabern verwendet wird, ist es klug, Hund als Detail zu behandeln und es zu verkapseln. Auf diese Weise sind sich einige Teile des Systems des Hundes völlig unbewusst und werden nicht beeinträchtigt, wenn wir uns mit "Papageien sind wir" verbinden.
Entkoppeln, trennen und verbergen Sie Details vom Rest des Codes. Lassen Sie nicht zu, dass sich das Wissen über Details in Ihrem System ausbreitet, und Sie werden "Kapseln, was variiert" genau verfolgen.
quelle
"Variiert" bedeutet hier "kann sich im Laufe der Zeit aufgrund sich ändernder Anforderungen ändern". Dies ist ein zentrales Konstruktionsprinzip: Trennung und Isolation von Codeteilen oder Daten, die in Zukunft möglicherweise separat geändert werden müssen. Wenn sich eine einzelne Anforderung ändert, sollte es im Idealfall nur erforderlich sein, den zugehörigen Code an einer einzigen Stelle zu ändern. Wenn die Codebasis jedoch schlecht konzipiert ist, dh stark miteinander verknüpft und die Logik für die Anforderung an vielen Stellen verteilt ist, ist die Änderung schwierig und birgt ein hohes Risiko, unerwartete Auswirkungen zu verursachen.
Angenommen, Sie haben eine Anwendung, in der an vielen Stellen die Umsatzsteuer berechnet wird. Wenn sich der Umsatzsteuersatz ändert, was würden Sie bevorzugen:
Der Umsatzsteuersatz ist überall in der Anwendung, wo die Umsatzsteuer berechnet wird, ein hartcodiertes Wort.
Der Umsatzsteuersatz ist eine globale Konstante, die überall dort verwendet wird, wo die Umsatzsteuer berechnet wird.
Es gibt eine einzige Methode, die aufgerufen wird.
calculateSalesTax(product)
Dies ist der einzige Ort, an dem der Umsatzsteuersatz verwendet wird.Der Umsatzsteuersatz wird in einer Konfigurationsdatei oder einem Datenbankfeld angegeben.
Da sich der Umsatzsteuersatz aufgrund einer politischen Entscheidung unabhängig von anderen Anforderungen ändern kann, ziehen wir es vor, ihn in einer Konfiguration zu isolieren, damit er ohne Auswirkung auf einen Code geändert werden kann. Es ist aber auch denkbar, dass sich die Logik zur Berechnung der Umsatzsteuer ändert, z. B. unterschiedliche Sätze für unterschiedliche Produkte. Deshalb möchten wir auch die Berechnungslogik gekapselt haben. Die globale Konstante scheint eine gute Idee zu sein, ist aber tatsächlich schlecht, da sie möglicherweise dazu anregt, die Umsatzsteuer an verschiedenen Stellen im Programm und nicht an einer einzigen Stelle zu verwenden.
Betrachten Sie nun eine andere Konstante, Pi, die auch an vielen Stellen im Code verwendet wird. Gilt das gleiche Konstruktionsprinzip? Nein, denn Pi wird sich nicht ändern. Das Extrahieren in eine Konfigurationsdatei oder ein Datenbankfeld führt nur zu unnötiger Komplexität (und wenn alles andere gleich ist, bevorzugen wir den einfachsten Code). Es ist sinnvoll, es zu einer globalen Konstante zu machen, anstatt es an mehreren Stellen fest zu codieren, um Inkonsistenzen zu vermeiden und die Lesbarkeit zu verbessern.
Der Punkt ist, wenn wir uns nur ansehen, wie das Programm jetzt funktioniert , Umsatzsteuersatz und Pi sind gleichwertig, beides sind Konstanten. Nur wenn wir uns überlegen, was in Zukunft anders sein kann , müssen wir sie im Design anders behandeln.
Dieses Prinzip ist eigentlich ziemlich tiefgreifend, da man über das hinausschauen muss, was die Codebasis heutzutage tun soll , und auch die externen Kräfte berücksichtigen muss, die dazu führen können, dass sie sich ändert, und sogar die verschiedenen Stakeholder verstehen muss, die hinter den Anforderungen stehen.
quelle
Beide aktuellen Antworten scheinen nur teilweise ins Schwarze getroffen zu haben und konzentrieren sich auf Beispiele, die die Kernidee trüben. Dies ist auch nicht (ausschließlich) ein OOP-Prinzip, sondern ein Software-Design-Prinzip im Allgemeinen.
Das, was in diesem Satz "variiert", ist der Code. Christophe ist der Meinung, dass es sich in der Regel um etwas handelt, das variieren kann , und dass Sie dies oft vorwegnehmen . Ziel ist es, sich vor zukünftigen Änderungen im Code zu schützen. Dies hängt eng mit der Programmierung an einer Schnittstelle zusammen . Christophe ist jedoch falsch, dies auf "Implementierungsdetails" zu beschränken. Tatsächlich beruht der Wert dieser Beratung häufig auf Änderungen der Anforderungen .
Dies hängt nur indirekt mit der Einkapselung des Staates zusammen, woran David Arno meines Erachtens denkt. Dieser Rat schlägt nicht immer (aber oft) vor, einen Zustand einzukapseln, und dieser Rat gilt auch für unveränderliche Objekte. Tatsächlich ist das bloße Benennen von Konstanten eine (sehr grundlegende) Form der Verkapselung von Unterschieden.
CandiedOrange kombiniert explizit "was variiert" mit "Details". Dies ist nur teilweise richtig. Ich bin damit einverstanden, dass jeder Code, der sich ändert, in gewissem Sinne "Details" ist, aber ein "Detail" darf nicht variieren (es sei denn, Sie definieren "Details", um dies tautologisch zu machen). Es mag Gründe geben, nicht variierende Details zu kapseln, aber dieses Diktum ist keines. Grob gesagt, wenn Sie sehr zuversichtlich wären, dass "Hund", "Katze" und "Ente" die einzigen Typen sind, mit denen Sie sich jemals auseinandersetzen müssten, dann schlägt dieses Sprichwort nicht vor, dass das Refactoring von CandiedOrange durchgeführt wird.
Wenn Sie das Beispiel von CandiedOrange in einem anderen Kontext betrachten, nehmen wir an, dass wir eine prozedurale Sprache wie C haben. Wenn ich Code habe, der Folgendes enthält:
Ich kann davon ausgehen, dass sich dieser Code in Zukunft ändern wird. Ich kann es einfach "einkapseln", indem ich eine neue Prozedur definiere:
und Verwenden dieser neuen Prozedur anstelle des Codeblocks (dh eines Refactorings mit "Extraktionsmethode"). Zu diesem Zeitpunkt muss nur die
speak
Prozedur aktualisiert werden, um einen "Kuh" -Typ oder etwas anderes hinzuzufügen . Natürlich können Sie in einer OO-Sprache stattdessen den dynamischen Versand nutzen, auf den die Antwort von CandiedOrange anspielt. Dies geschieht natürlich, wenn Siepet
über eine Schnittstelle zugreifen . Die Beseitigung der bedingten Logik durch dynamisches Versenden ist eine orthogonale Angelegenheit, die ein Teil des Grundes war, warum ich diese prozedurale Wiedergabe gemacht habe. Ich möchte auch betonen, dass dies keine OOP-spezifischen Funktionen erfordert. Selbst in einer OO-Sprache muss nicht unbedingt eine neue Klasse oder Schnittstelle erstellt werden, um die Variationen zu kapseln.Als eher archetypisches Beispiel (das näher an, aber nicht ganz OO ist) möchten wir die Duplikate aus einer Liste entfernen. Nehmen wir an, wir implementieren es, indem wir die Liste nachverfolgen, die wir bisher in einer anderen Liste gesehen haben, und alle Elemente entfernen, die wir gesehen haben. Es ist vernünftig anzunehmen, dass wir möglicherweise aus Gründen der Leistung ändern möchten, wie wir den Überblick über die angezeigten Elemente behalten. Das Sprichwort, was variiert, legt nahe, dass wir einen abstrakten Datentyp erstellen sollten, um die Menge der gesehenen Elemente darzustellen. Unser Algorithmus ist jetzt für diesen abstrakten Datentyp "Set" definiert. Wenn wir zu einem binären Suchbaum wechseln, muss sich unser Algorithmus nicht ändern oder kümmern. In einer OO-Sprache verwenden wir möglicherweise eine Klasse oder Schnittstelle, um diesen abstrakten Datentyp zu erfassen. In einer Sprache wie SML / O '
Angenommen, Sie müssen für ein anforderungsorientiertes Beispiel ein Feld in Bezug auf eine Geschäftslogik validieren. Möglicherweise haben Sie jetzt bestimmte Anforderungen, aber Sie vermuten stark, dass sich diese weiterentwickeln werden. Sie können die aktuelle Logik in einer eigenen Prozedur / Funktion / Regel / Klasse einkapseln.
Obwohl dies ein orthogonales Anliegen ist, das nicht Teil von "verkapseln, was variiert" ist, ist es oft natürlich, das zu abstrahieren, was durch die jetzt verkapselte Logik parametrisiert wird. Dies führt normalerweise zu flexiblerem Code und ermöglicht das Ändern der Logik durch Ersetzen in einer alternativen Implementierung, anstatt die gekapselte Logik zu modifizieren.
quelle
"Verkapseln, was variiert" bezieht sich auf das Verbergen von Implementierungsdetails, die sich ändern und weiterentwickeln können.
Beispiel:
Angenommen, die Klasse
Course
verfolgt,Students
dass register () registriert werden kann. Sie können es mit a implementierenLinkedList
und den Container verfügbar machen, um eine Iteration zu ermöglichen:Das ist aber keine gute Idee:
Wenn Sie verkapseln, was variiert (oder vielmehr gesagt wird, was variieren könnte), behalten Sie die Freiheit, dass sowohl der verwendende Code als auch die gekapselte Klasse sich gegenseitig entwickeln können. Deshalb ist es ein wichtiges Prinzip in OOP.
Zusätzliche Lektüre:
quelle