16 Stimmen

Verstößt Dependency Injection gegen das Gesetz von Demeter?

Ich habe die Injektion von Abhängigkeiten zu meinem Code hinzugefügt, weil es den Code viel einfacher macht, durch Mocking einen Unit-Test durchzuführen.

Ich verlange jedoch, dass Objekte, die weiter oben in meiner Aufrufkette stehen, Kenntnis von Objekten haben, die weiter unten in der Aufrufkette stehen.

Verstößt dies gegen das Gesetz der Demeter? Wenn ja, ist das von Bedeutung?

Beispiel: Eine Klasse A hat eine Abhängigkeit von einer Schnittstelle B. Die zu verwendende Implementierung dieser Schnittstelle wird in den Konstruktor der Klasse A injiziert. Jeder, der die Klasse A verwenden will, muss nun auch einen Verweis auf eine Implementierung von B haben und kann deren Methoden direkt aufrufen, d.h. er hat Kenntnis von deren Unterkomponenten (Schnittstelle B)

Wikipedia sagt über das Gesetz der Demeter: "Der grundlegende Gedanke ist, dass ein bestimmtes Objekt so wenig wie möglich von der Struktur oder den Eigenschaften eines anderen Objekts (einschließlich seiner Teilkomponenten) annehmen sollte."

1 Stimmen

Können Sie einen Beispielcode veröffentlichen? Wenn Sie foo.bar().baz() machen, dann verstoßen Sie gegen das Gesetz von Demeter. Wollen Sie damit sagen, dass Sie am Ende so vorgehen?

1voto

klenki Punkte 278

Das hat mich auch eine Zeit lang verwirrt. In der wiki heißt es auch...

Ein Objekt A kann einen Dienst (Aufruf einer Methode) einer Objektinstanz B anfordern, aber Objekt A sollte nicht durch Objekt B "hindurchgreifen", um auf ein weiteres Objekt, C, zuzugreifen und dessen Dienste anzufordern. Dies würde bedeuten, dass Objekt A implizit mehr Wissen über die interne Struktur von Objekt B benötigt.

Und genau das ist der springende Punkt. Wenn Sie mit der Klasse A interagieren, sollten Sie nicht in der Lage sein, mit dem Zustand oder den Methoden der Schnittstelle B zu interagieren. Sie sollten einfach keinen Zugang zu ihrem Innenleben haben.

Was die Erstellung von Klasse A und die Kenntnis der Schnittstelle B bei der Erstellung von Objekten angeht, so ist das ein ganz anderes Szenario, das nicht Gegenstand des Demeter-Gesetzes für die Softwareentwicklung ist.

Ich würde mit anderen Antworten zustimmen, dass Fabriken und eine Abhängigkeit Injektion Rahmen wäre am besten, dies zu behandeln. Hoffe, dass es bis für alle anderen verwirrt durch diese klärt :)

0voto

Kommt drauf an :-)

Ich denke, die oberste Antwort ist nicht korrekt, auch mit einem Rahmen eine Menge von Code verwendet Dependency Injection und injiziert High-Level-Objekte. Sie erhalten dann Spaghetti-Code mit vielen Abhängigkeiten.

Dependency Injection wird am besten für all die Dinge verwendet, die Ihr Objektmodell verschmutzen würden, z. B. ein ILogger. Wenn Sie ein Geschäftsobjekt injizieren, stellen Sie sicher, dass es auf der niedrigsten Ebene möglich ist und versuchen Sie, es mit der traditionellen Methode zu übergeben, wenn Sie können. Verwenden Sie die Dependency Injection nur, wenn es zu unübersichtlich wird.

0voto

Suamere Punkte 4914

Bevor ich meine Antwort hinzufüge, muss ich sie relativieren. Die serviceorientierte Programmierung baut auf OOP-Prinzipien auf und verwendet OO-Sprachen. Außerdem folgen SOAs den Grundsätzen der Inversion of Control und SOLID bis ins Detail. Es werden also sicherlich viele serviceorientierte Programmierer hier ankommen. Diese Antwort ist also für Service-orientierte Programmierer gedacht, die diese Frage stellen, da SOA auf OOP aufbaut. Dies ist keine direkte Antwort auf das Beispiel des Auftraggebers, aber es beantwortet die Frage aus einer SOA-Perspektive.

Im Allgemeinen gilt das Gesetz von Demeter nicht für Service-orientierte Architekturen. Für OO spricht das Gesetz von Demeter von "Rich Objects" in OOP, die Eigenschaften und Methoden haben, und deren Eigenschaften auch Methoden haben können. Mit OOP Rich Models ist es möglich, eine Kette von Objekten zu durchlaufen und auf Methoden, Eigenschaften, Methoden von Eigenschaften, Methoden von Eigenschaften von Eigenschaften usw. zuzugreifen. In der serviceorientierten Programmierung sind die Daten (Eigenschaften) jedoch vom Prozess (Methoden) getrennt. Ihre Modelle haben (hauptsächlich) nur Eigenschaften (aber niemals Abhängigkeiten), und Ihre Dienste haben nur Methoden und Abhängigkeiten von anderen Diensten.

In SOP können Sie die Eigenschaften eines Modells und die Eigenschaften seiner Eigenschaften nachlesen. Sie werden niemals auf Methoden zugreifen können, die Sie nicht verwenden sollten, sondern nur auf einen Baum von Daten. Aber was ist mit den Diensten? Gilt dort das Gesetz der Demeter?

Ja, das Gesetz der Demeter Kann sein auf SOP Services angewandt. Aber auch hier gilt, dass das Gesetz ursprünglich für Rich Models in OOP konzipiert wurde. Und obwohl das Gesetz Kann sein auf Dienste angewandt wird, erfüllt die richtige Dependency Injection automatisch das Gesetz der Demeter. In diesem Sinne kann DI das Gesetz unmöglich brechen.

Im Gegensatz zu Mark Roddy kann ich keine Situation finden, in der man legitimerweise über Dependency Injection und "Verbraucher" im selben Satz sprechen kann. Wenn Sie mit "Konsumenten" eine Klasse meinen, die eine andere Klasse konsumiert, dann macht das keinen Sinn. Mit DI würden Sie eine Composition Root haben, die Ihren Objektgraphen zusammensetzt, und eine Klasse sollte nie wissen, dass eine andere Klasse überhaupt existiert. Wenn Sie mit "Konsumenten" einen Programmierer meinen, wie würden sie dann no gezwungen werden, "die Injektion durchzuführen". Der Programmierer ist derjenige, der die Kompositionswurzel erstellen muss, also muss er auch die Injektion vornehmen. Ein Programmierer sollte niemals "die Injektion" als Instanziierung innerhalb einer Klasse vornehmen, um eine andere Klasse zu konsumieren.

Sehen Sie sich das folgende Beispiel an, das tatsächliche separate Lösungen, ihre Referenzen und den Implementierungscode zeigt:

In SOA, DI doesn't allow breaking of LoD

Oben rechts befindet sich der "Kern". Viele Pakete auf NuGet und NPM haben ein "Core"-Projekt, das Model, Interfaces und möglicherweise sogar Standardimplementierungen enthält. Der Kern sollte niemals von etwas Externem abhängen.

Oben links haben wir eine externe Implementierung des Core. Die Implementierung hängt vom Core ab und hat daher Kenntnis von ihm.

Unten links befindet sich ein eigenständiger Bereich. Der Bereich hat eine Abhängigkeit von einer Implementierung des Kerns, aber Er muss nichts über die Umsetzung wissen .

An dieser Stelle weise ich darauf hin, dass weder der Bereich noch die Durchführung wissen, dass der andere existiert. Es besteht eine 0%ige Chance, dass einer der beiden jemals in den anderen hinein (oder darüber hinaus) gelangen kann, weil sie nicht einmal wissen, dass sie existieren. Die Domäne weiß nur, dass es einen Vertrag gibt, und sie kann irgendwie die Methoden von was auch immer in sie injiziert wird konsumieren.

Unten links befindet sich die Kompositionswurzel oder der Einstiegspunkt. Er wird auch als "vordere Begrenzung" der Anwendung bezeichnet. Die Wurzel einer Anwendung kennt alle ihre Komponenten und tut nicht viel mehr, als Eingaben entgegenzunehmen, zu bestimmen, wer angerufen werden soll, Objekte zu komponieren und Ausgaben zurückzugeben. Mit anderen Worten, sie kann dem Bereich nur sagen: "Hier, benutze dies, um deinen Vertrag für ICalculateThings zu erfüllen, und gib mir dann das Ergebnis von CalculateTwoThings.

Es gibt in der Tat einen Weg, um alles in das gleiche Projekt zu zerschlagen, tun konkrete Instanziierungen von Services, machen Sie Ihre Abhängigkeiten öffentliche Eigenschaften anstelle von privaten Feldern, STILL Do Dependency-Injection (schrecklich), und dann haben Dienste in Abhängigkeiten von Abhängigkeiten aufrufen. Aber das wäre schlecht, m'kay. Man müsste schon versuchen, schlecht zu sein, um das zu tun.

Nebenbei bemerkt, ich habe es absichtlich zu kompliziert gemacht. Diese Projekte könnten in einer Lösung existieren (solange der Architekt die Referenzarchitektur kontrolliert), und es könnte noch ein paar weitere Vereinfachungen geben. Aber die Trennung im Bild zeigt wirklich, wie wenig das System über seine Teile wissen muss. Nur die Kompositionswurzel (Einstiegspunkt, Front-Boundary) muss über die Teile Bescheid wissen.

Fazit (TL;DR;): In Oldskewl OOP sind Modelle reichhaltig, und das Gesetz der Demeter kann leicht gebrochen werden, indem man in Modelle von Modellen schaut, um auf ihre Methoden zuzugreifen. In Newskewl SOP (das auf den OOP-Prinzipien und -Sprachen aufbaut) sind die Daten jedoch vom Prozess getrennt. Sie können sich also mit den Eigenschaften von Modellen befassen. Bei Diensten sind Abhängigkeiten immer privat, und nichts weiß, dass etwas anderes existiert als das, was ihnen durch Abstraktionen, Verträge und Schnittstellen mitgeteilt wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X