Kernpunkte
Softwareprogrammierung ist eine ausgewogene Kombination aus Kunst (manchmal Euphemismus zur Improvisation) und vielen bewährten Heuristiken, um bestimmte Probleme zu lösen und sie auf anständige Weise zu lösen. Nur wenige Menschen würden nicht zustimmen, dass der künstlerische Aspekt bei weitem am schwierigsten ist, um zu heiraten und zu verfeinern. Andererseits ist die Kraft hinter Heuristiken wichtig, um Software basierend auf gutem Design zu entwickeln. Bei so vielen Heuristiken, die erklären, wie und warum Softwaresysteme sich an bestimmte Methoden halten sollten, ist es ziemlich enttäuschend, sie in der PHP -Welt nicht weiter implementiert zu sehen. Zum Beispiel kann das dimitianische Gesetz eines der am stärksten unterschätzten Gesetze im Bereich Sprachbereich sein. Tatsächlich scheint das Motto der Regel „nur mit Ihren engen Freunden zu sprechen“ in einem ziemlich unreifen Zustand in PHP zu sein, was zu einem Rückgang der Gesamtqualität mehrerer objektorientierter Codebasis geführt hat. Einige beliebte Frameworks drängen es aktiv voran, um sich mehr an die Vorschriften des Gesetzes zu halten. Es macht keinen Sinn, sich gegenseitig die Schuld für Verstoß gegen das dimitesische Gesetz zu beschuldigen, denn der beste Weg, eine solche Zerstörung zu mildern . Um sich der Sache der Gerechtigkeit anzuschließen und das Gesetz aus praktischer Sicht besser zu studieren Zeit kann die Effizienz wirklich verbessern.
Es ist nicht gut, zu viel zu wissen
wird oft als Prinzip des geringsten Wissens bezeichnet, und die durch das dimitese Gesetz befürworteten Regeln sind leicht zu verstehen. Einfach ausgedrückt, nehmen Sie an, Sie haben eine gut gestaltete Klasse, die eine bestimmte Methode implementiert, und dann sollte die Methode darauf beschränkt sein, andere Methoden zu rufen, die zum folgenden Objekt gehören:
Obwohl die Liste alles andere als formal ist (für formellere Listen, schauen Sie sich Wikipedia an), sind diese wichtigen Punkte leicht zu verstehen. Im traditionellen Design wird es als falsch angesehen, zu viel über ein anderes Objekt zu wissen (das implizit das Wissen, wie man auf ein drittes Objekt zugreift) Es muss wie erwartet funktionieren. Dies ist aus offensichtlichen Gründen ein schwerwiegender Designfehler. Der Anrufer hat ein ziemlich umfangreiches und detailliertes Verständnis der internen Struktur des Zwischenprodukts, auch wenn dies über mehrere Getter zugegriffen wird. Darüber hinaus zeigt die Verwendung von Zwischenobjekten, um das vom Anrufer verlangte Objekt zu erhalten, ein Problem an sich. Wenn dasselbe Ergebnis durch direkte Injektion der Abhängigkeiten erzielt werden kann, warum sollten Sie einen solchen komplexen Pfad verwenden, um die Abhängigkeiten zu erhalten oder eine seiner Methoden aufzurufen? Dieser Prozess hat überhaupt keine Bedeutung.
Nehmen wir an, wir müssen ein Dateispeichermodul erstellen, das einen polymorphen Encoder intern verwendet, um Daten in die angegebene Zieldatei zu ziehen und zu speichern. Wenn wir das Modul absichtlich schlampig an einen injizierbaren Service -Locator verbinden, sieht seine Implementierung so aus:
<?php namespace LibraryFile; use LibraryDependencyInjectionServiceLocatorInterface; class FileStorage { const DEFAULT_STORAGE_FILE = "data.dat"; private $locator; private $file; public function __construct(ServiceLocatorInterface $locator, $file = self::DEFAULT_STORAGE_FILE) { $this->locator = $locator; $this->setFile($file); } public function setFile($file) { if (!is_readable($file) || !is_writable($file)) { throw new InvalidArgumentException( "The target file is invalid."); } $this->file = $file; return $this; } public function write($data) { try { return file_put_contents($this->file, $this->locator->get("encoder")->encode($data), LOCK_EX); } catch (Exception $e) { throw new $e( "Error writing data to the target file: " . $e->getMessage()); } } public function read() { try { return $this->locator->get("encoder")->decode( @file_get_contents($this->file)); } catch(Exception $e) { throw new $e( "Error reading data from the target file: " . $e->getMessage()); } } }
Lassen Sie einige irrelevante Implementierungsdetails aus und konzentrieren sich auf den Konstruktor der FileStorage -Klasse und deren Write () und Read (). Diese Klasse injiziert eine Instanz eines Service -Locators, der nicht definiert wurde und später verwendet wird, um Abhängigkeiten (den oben genannten Encoder) abzurufen, um Daten in der Zieldatei abzurufen und zu speichern. Dies ist normalerweise ein Verstoß gegen das Dimitter -Gesetz, wenn man bedenkt, dass die Klasse zuerst den Locator durchquert und dann den Encoder erreicht. Caller FileStorage weiß zu viel über die interne Struktur des Locators, einschließlich des Zugriffs auf den Encoder, was definitiv keine Fähigkeit ist, die ich loben möchte. Es ist ein Artefakt, das von Natur aus in der Natur eines Dienstleistungsortes (weshalb manche Menschen es als Anti-Muster betrachten) oder eine andere Art von statischer oder dynamischer Registrierung, auf die ich zuvor hingewiesen habe. Um dieses Problem ein umfassenderes Verständnis zu erhalten, lesen wir die Implementierung des Locators:
(Die Codes von Locator und Encoder sind hier weggelassen, da sie mit der vorherigen Ausgabe übereinstimmen. Um eine Duplikation zu vermeiden, werde ich sie hier nicht wiederholen.)
Beginnen wir mit dem Encoder mit allen Beispielklassen zusammen:
(Der Verwendung von Verwendung wird hier weggelassen, da er mit der vorherigen Ausgabe übereinstimmt. Um eine Duplikation zu vermeiden, werde ich ihn hier nicht wiederholen.)
Verstöße gegen dieses Gesetz sind in diesem Fall ein eher verdeckter Problem und sind schwer von der Oberfläche zu verfolgen, mit Ausnahme der Verwendung des Mutators des Locators, was darauf hindeutet und benutzen. In jedem Fall zeigt die Tatsache, dass wir wissen, dass der Verstoß außerhalb der Außenwelt versteckt ist, nicht nur zu viele Informationen über die Locator -Struktur, sondern auch unnötig die FileStorage -Klasse für den Locator selbst. Befolgen Sie einfach die Regeln dieser Regel und lassen Sie den Locator entfernen. Wir können die Kopplung entfernen und gleichzeitig die tatsächlichen Mitarbeiter, die sie benötigt, um ihre Geschäfte zu machen, zu vermitteln. Es gibt keine ungeschickten, exponierten Zwischenprodukte auf dem Weg! Glücklicherweise kann all dieser Unsinn leicht in Arbeitscode umgewandelt werden. Sehen Sie sich einfach die erweiterte, dimitri-konforme Version der Filestorage-Klasse hier an:
(Der refaktorierte Filestorage -Code wird hier weggelassen, da er mit der vorherigen Ausgabe übereinstimmt. Um eine Duplikation zu vermeiden, werde ich ihn hier nicht wiederholen.)
Dies ist in der Tat leicht zu refaktor. Die Klasse verwendet nun direkt einen Implementierer der CCCerinterface -Schnittstelle, wodurch die interne Struktur unnötiger Zwischenprodukte durchquert wird. Das Beispiel ist zweifellos trivial, veranschaulicht jedoch einen Punkt der Gültigkeit und zeigt, warum es eines der besten Dinge ist, die Sie den Vorschriften des Dimitri -Gesetzes befolgen, um das Design der Klasse zu verbessern. Ein Sonderfall dieser Regel wird jedoch in Robert Martins Buch "The Way of Code: Agile Software Development Manual" zutiefst untersucht und verdient eine besondere Analyse. Bitte nehmen Sie sich einen Moment Zeit, um sorgfältig nachzudenken: Was passiert, wenn FileStorage als Kollaborateur durch ein Datenübertragungsobjekt (DTO) definiert wird?
(Das Codebeispiel wird hier weggelassen, da es mit der vorherigen Ausgabe übereinstimmt, und um eine Duplikation zu vermeiden, werde ich sie hier nicht wiederholen.)
Dies ist definitiv eine interessante Möglichkeit, Dateispeicherklassen zu implementieren, da jetzt injizierbare DTOs verwendet werden, um Encoder intern zu übertragen und zu verwenden. Die Frage, die beantwortet werden muss, ist, ob diese Methode wirklich gegen das Gesetz verstößt. Aus puristischer Sicht verstößt es, weil DTO zweifellos ein Zwischenprodukt ist, das seine gesamte Struktur dem Anrufer aussetzt. DTO ist jedoch nur eine normale Datenstruktur, im Gegensatz zu früheren Service -Locators verhalten sie sich überhaupt nicht. Und der Zweck der Datenstruktur ist ... ja, ihre Daten offenzulegen. Dies bedeutet, dass das Dimitter -Gesetz intakt bleibt, solange das Intermediate das Verhalten nicht implementiert (was genau das Gegenteil des Verhaltens einer regulären Klasse ist, die seine Daten versteckt, weil es das Verhalten enthüllt). Das folgende Code -Snippet zeigt, wie die FileStorage mit dem problematischen DTO verwendet wird:
(Das Codebeispiel wird hier weggelassen, da es mit der vorherigen Ausgabe übereinstimmt, und um eine Duplikation zu vermeiden, werde ich sie hier nicht wiederholen.)
Dieser Ansatz ist viel schwieriger, als einen Encoder direkt in eine Dateispeicherklasse zu übergeben. Das Beispiel zeigt jedoch, dass einige schwierige Implementierungen, die auf den ersten Blick auf eklige Verstöße gegen das Gesetz sind, normalerweise ziemlich harmlos sind, so lange wie Sie verwenden nur eine Datenstruktur ohne zusätzliches Verhalten.
Schlussfolgerung
Da verschiedene komplexe, manchmal esoterische Heuristiken in OOP beliebt sind, erscheint es bedeutungslos, ein weiteres Prinzip hinzuzufügen, das offensichtlich keine offensichtlichen positiven Auswirkungen auf das Design von Schichtkomponenten hat. Das Dimitter -Gesetz ist jedoch keineswegs ein Prinzip, das in der realen Welt kaum angewendet wird. Trotz seines wunderschönen Namens ist das Dimitt Law ein leistungsstarkes Paradigma mit dem Hauptziel, die Implementierung hochkarätiger Anwendungskomponenten durch Beseitigung unnötiger Zwischenprodukte zu erleichtern. Folgen Sie einfach seinen Vorschriften und sein natürlich nicht blind dogmatisch und Sie werden eine Verbesserung der Codequalität sehen. sicherstellen.
(Der FAQS -Teil wird hier weggelassen, da er mit der vorherigen Ausgabe übereinstimmt. Um eine Duplikation zu vermeiden, werde ich sie hier nicht wiederholen.)
Das obige ist der detaillierte Inhalt vonPHP Master | Einführung in das Gesetz des Demeter. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!