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:
if (pet.type() == dog) {
pet.bark();
} else if (pet.type() == cat) {
pet.meow();
} else if (pet.type() == duck) {
pet.quack()
}
Ich kann davon ausgehen, dass sich dieser Code in Zukunft ändern wird. Ich kann es einfach "einkapseln", indem ich eine neue Prozedur definiere:
void speak(pet) {
if (pet.type() == dog) {
pet.bark();
} else if (pet.type() == cat) {
pet.meow();
} else if (pet.type() == duck) {
pet.quack()
}
}
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 Sie pet
ü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.