Ich habe drei Fragen zum Demeter-Gesetz.
Abgesehen von Klassen, der Rückkehr Objekten speziell ernannt wurden - wie Fabrik und Erbauer Klassen - ist es in Ordnung , für eine Methode ein Objekt zurück, zB ein Objekt gehalten durch eine der Eigenschaften der Klasse oder würde , die verletzen das Gesetz des demeter (1) ? Und wenn es gegen das Gesetz der Demeter verstößt, wäre es dann von Bedeutung, wenn das zurückgegebene Objekt ein unveränderliches Objekt ist, das ein Datenelement darstellt und nur Getter für diese Daten enthält (2a)? Oder ist solch ein ValueObject ein Anti-Pattern an sich, weil alles, was mit den Daten in dieser Klasse gemacht wird, außerhalb der Klasse gemacht wird (2b)?
Im Pseudocode:
class A {}
class B {
private A a;
public A getA() {
return this.a;
}
}
class C {
private B b;
private X x;
public void main() {
// Is it okay for B.getA to exist?
A a = this.b.getA();
a.doSomething();
x.doSomethingElse(a);
}
}
Ich vermute, dass Demeters Gesetz ein Muster wie das obige verbietet. Was kann ich tun, um sicherzustellen, dass doSomethingElse()
bei Nichtbeachtung des Gesetzes (3) angerufen werden kann?
quelle
x
es gemacht?x
ist nur eine andere Eigenschaft, deren Wert nur ein Objekt ist, das aufgerufen werden kanndoSomethingElse
.user.currentSession.isLoggedIn()
. weil es Paare Kundenuser
nicht nur ,user
sondern auch seine Mitarbeiter,session
. Stattdessen möchten Sie schreiben könnenuser.isLoggedIn()
. Dies wird normalerweise durch Hinzufügen einerisLoggedIn
Methode erreicht, anuser
deren Implementierung delegiert wirdcurrentSession
.Antworten:
In vielen Programmiersprachen sind alle zurückgegebenen Werte Objekte. Wie andere bereits gesagt haben, zwingt Sie die Unfähigkeit, die Methoden von zurückgegebenen Objekten zu verwenden, dazu, niemals etwas zurückzugeben. Sie sollten sich fragen: "Was sind die Aufgaben der Klassen A, B und C?" Aus diesem Grund fordern metasyntaktische Variablennamen wie A, B und C immer die Antwort "es hängt davon ab" an, da in diesen Begriffen keine erblichen Verantwortlichkeiten enthalten sind.
Vielleicht möchten Sie sich mit domänengetriebenem Design befassen, das Ihnen differenziertere Heuristiken bietet, um zu überlegen, wohin die Funktionalität gehen soll und wer was aufrufen soll.
Ihre zweite Frage zu unveränderlichen Objekten bezieht sich auf den Begriff eines
Wertobjekts im Vergleich zu einem Entitätsobjekt. In DDD können Sie Wertobjekte nahezu uneingeschränkt weitergeben. Dies gilt nicht für Entitätsobjekte.
Die vereinfachte LOD wird in DDD viel besser ausgedrückt als die Regeln für den Zugriff auf Aggregate . Keine externen Objekte sollten Verweise auf Mitglieder von Aggregaten enthalten. Es sollte nur ein Stammverweis gespeichert werden.
Abgesehen von DDD möchten Sie zumindest eigene Gruppen von Stereotypen für Ihre Klassen entwickeln, die für Ihre Domain angemessen sind. Erzwingen Sie beim Entwerfen Ihres Systems Regeln zu diesen Stereotypen.
Denken Sie auch immer daran, dass alle diese Regeln dem Umgang mit Komplexität dienen und nicht dazu, sich selbst zu behindern.
quelle
Law of Demeter
,tell, don't ask
,getters are evil
,object encapsulation
undsingle responsibility principle
scheinen auf diese Frage einkochen: wann sollte eine Delegation zu einem Domänenobjekt verwendet werden , im Gegensatz zu dem Objektwert bekommen und mit ihm etwas zu tun? Es wäre sehr nützlich, differenzierte Qualifikationen auf Situationen anwenden zu können, in denen eine solche Entscheidung getroffen werden muss.Ja, das ist es mit Sicherheit.
Schauen wir uns die wichtigsten Punkte an :
Alle drei lassen Sie eine Frage stellen: Wer ist ein Freund?
Bei der Entscheidung, was zurückgegeben werden soll, schreibt das Gesetz von Demeter oder das Prinzip des geringsten Wissens (LoD) nicht vor, dass Sie sich gegen Programmierer verteidigen, die darauf bestehen, gegen das Gesetz zu verstoßen. Es schreibt vor, dass Sie Codierer nicht dazu zwingen, dagegen zu verstoßen.
Diese zu verwirren ist genau der Grund, warum so viele glauben, ein Setter müsse immer ins Leere gehen. Nein. Sie müssen die Möglichkeit einräumen, Abfragen (Getter) durchzuführen, die den Status des Systems nicht ändern. Das ist die grundlegende Trennung von Befehlsabfragen .
Bedeutet dies, dass Sie sich frei in eine Codebasis vertiefen können, die alles miteinander verkettet, was Sie wollen? Verketten Sie nur das, was zusammen verkettet werden sollte. Andernfalls könnte sich die Kette ändern und plötzlich ist Ihr Zeug kaputt. Dies ist, was mit Freunden gemeint ist.
Lange Ketten können für ausgelegt werden. Fließende Schnittstellen, iDSL, ein Großteil von Java8 und der gute alte StringBuilder ermöglichen den Aufbau langer Ketten. Sie verletzen LoD nicht, weil alles in der Kette zusammenarbeiten soll und versprochen wird, weiter zusammenzuarbeiten. Sie verletzen Demeter, wenn Sie Dinge aneinander reihen, die noch nie voneinander gehört haben. Freunde sind diejenigen, die versprochen haben, Ihre Kette am Laufen zu halten. Freunde von Freunden nicht.
Dies schafft nur die Möglichkeit, gegen Demeter zu verstoßen. Dies ist keine Verletzung. Das ist nicht unbedingt schlecht.
Unveränderlich ist hier gut, aber irrelevant. Dinge durch eine längere Kette zu erreichen, macht es nicht besser. Was es besser macht, ist das Trennen des Erhaltens vom Verwenden. Wenn Sie verwenden, fragen Sie nach dem, was Sie als Parameter benötigen. Gehen Sie nicht auf die Jagd, indem Sie sich mit Fremden befassen.
Bevor ich darüber
x.doSomethingElse(a)
spreche, verstehe ich , dass du grundlegend geschrieben hastb.getA().doSomething()
Jetzt ist LoD keine Punktezählübung . Aber wenn Sie eine Kette erstellen, sagen Sie, dass Sie wissen, wie man eine
A
(mitB
) erhält und wie man eine verwendetA
. Nun gutA
undB
besser enge Freunde sein, weil du sie einfach zusammengekoppelt hast.Wenn Sie nur darum gebeten hätten, Ihnen etwas
A
Ähnliches zu geben, das Sie verwenden könnten,A
und es hätte Sie nicht interessiert, woher es kommt, und SieB
könnten ein Leben führen, das glücklich und frei von Ihrer Obsession ist,A
davon zu lebenB
.Was die Herkunft
x.doSomethingElse(a)
ohne Detailsx
angeht, hat LoD überhaupt nichts zu sagen.LoD kann die Trennung von Nutzung und Konstruktion fördern . Aber ich werde darauf hinweisen, wenn Sie jedes Objekt religiös als nicht freundlich behandeln, werden Sie nicht in der Lage sein, Code in statischen Methoden zu schreiben. Sie können auf diese Weise einen wunderbar komplexen Objektgraphen erstellen, aber irgendwann müssen Sie eine Methode darauf aufrufen, um das Ding zum Laufen zu bringen. Sie müssen sich nur entscheiden, wer Ihre Freunde sind. Daran führt kein Weg vorbei.
Ja, eine Klasse darf eines ihrer Mitglieder unter LoD zurückgeben. Wenn Sie dies tun, sollten Sie klarstellen, ob dieses Mitglied mit Ihrer Klasse befreundet ist. Andernfalls versucht ein Client möglicherweise, Sie an diese Klasse zu koppeln, indem Sie Sie verwenden, um sie abzurufen, bevor Sie sie verwenden. Das ist wichtig, denn jetzt muss das, was Sie zurückgeben, diese Verwendung immer unterstützen.
Es gibt viele Fälle, in denen dies einfach kein Problem darstellt. Sammlungen können dies einfach ignorieren, weil sie mit allem, was sie verwendet, befreundet sein sollen. Ähnlich wertvolle Objekte sind mit jedem freundlich. Wenn Sie jedoch ein Dienstprogramm zur Adressvalidierung geschrieben haben, das ein Mitarbeiterobjekt anfordert, aus dem eine Adresse extrahiert wurde, und dann nur nach der Adresse fragen, sollten Sie hoffen, dass sowohl Mitarbeiter als auch Adresse aus derselben Bibliothek stammen.
quelle
settings.darkTheme().monospaceFont()
ist nur syntaktischer Zucker fürsettings.darkTheme(); settings.monospaceFont();
Ich verstehe dieses Argument nicht ganz. Jedes Objekt kann ein Objekt als Ergebnis eines Nachrichtenaufrufs zurückgeben. Vor allem, wenn Sie an "alles als Objekt" denken.
Klassen sind jedoch die einzigen Objekte, die neue Objekte ihrer Art instanziieren können, indem sie ihnen die "neue" Nachricht senden (oder in den meisten gängigen OOP-Sprachen häufig durch ein neues Schlüsselwort ersetzt werden).
Was Ihre Frage betrifft, wäre ich ziemlich misstrauisch, wenn ein Objekt eine seiner Eigenschaften zurückgibt, um anderweitig verwendet zu werden. Es könnte sein, dass dieses Objekt Informationen über seinen Status oder seine Implementierungsdetails preisgibt.
Und Sie möchten nicht, dass das C-Objekt die Implementierungsdetails von B kennt. Dies ist eine unerwünschte Abhängigkeit vom A-Objekt aus der C-Objektperspektive.
Vielleicht möchten Sie sich fragen, ob C, wenn es A kennt, nicht zu viel weiß für die Arbeit, die es unabhängig von der LOD zu tun hat.
Es gibt Fälle, in denen dies legitim sein kann, z. B. wenn ein Erfassungsobjekt nach einem seiner Elemente gefragt wird und keine Demeter-Regel verletzt wird. Es ist riskant und sollte vermieden werden, ein Book-Objekt nach seinem SQLConnection-Objekt zu fragen.
Die LOD existiert, weil viele Programmierer dazu neigen, Objekte nach Informationen zu fragen, bevor sie eine Arbeit daraus ausführen. LOD ist da, um uns daran zu erinnern, dass wir manchmal (wenn nicht immer) die Dinge nur überkomplizieren, indem wir wollen, dass unsere Objekte zu viel bewirken. Manchmal müssen wir nur einen anderen Gegenstand bitten, die Arbeit für uns zu erledigen. LOD ist da, um uns Gedanken darüber zu machen, wo wir das Verhalten in unsere Objekte einfügen.
quelle
Warum sollte es nicht so sein? Sie scheinen vorzuschlagen, dass Sie Ihren Programmiererkollegen signalisieren müssen, dass die Klasse speziell zum Zurückgeben von Objekten gedacht ist, oder dass sie überhaupt keine Objekte zurückgeben darf. In Sprachen, in denen alles ein Objekt ist, würde dies Ihre Optionen erheblich einschränken, da Sie überhaupt nichts zurückgeben können.
quelle
b.getA().doSomething()
undx.doSomethingElse(b.getA())
A a = b.getA(); a.DoSomething();
- Zurück zu einem Punkt.b.getA().doSomething()
undx.doSomethingElse(b.getA())
Sie explizit danach hätten fragen sollen. Wie es aussieht, scheint Ihre Frage zu seinthis.b.getA()
.A
es kein Mitglied von istC
, in dem es nicht erstellt wurdeC
und für das es nicht bereitgestellt wirdC
, scheint es, dass die VerwendungA
inC
(auf welche Weise auch immer) gegen die LoD verstößt. Punkte zählen ist nicht das, worum es bei LoD geht, es ist nur ein anschauliches Werkzeug. Es ist möglich,Driver().getCar().getSteeringWheel().getFrontWheels().toRight()
Anweisungen, die jeweils einen Punkt enthalten , in separate Anweisungen umzuwandeln , aber die Verletzung von LoD ist weiterhin vorhanden. Ich habe in vielen Beiträgen in diesem Forum gelesen, dass das Ausführen von Aktionen an das Objekt delegiert werden sollte, das das tatsächliche Verhalten implementiert, dtell don't ask
. H. Die Rückgabe von Werten scheint dem zu widersprechen.Kommt darauf an, was du tust. Wenn Sie ein Mitglied Ihrer Klasse aussetzen, wenn es niemanden interessiert, dass es sich um ein Mitglied Ihrer Klasse handelt, oder um den Typ dieses Mitglieds, ist das eine schlechte Sache. Wenn Sie dann den Typ dieses Members und den Typ der Funktion ändern, die das Member zurückgibt, und jeder seinen Code ändern muss, ist das böse.
Wenn die Schnittstelle Ihrer Klasse dagegen angibt, dass sie eine Instanz einer bekannten Klasse A liefert, ist das in Ordnung. Wenn Sie Glück haben und dies tun können, indem Sie ein Mitglied Ihrer Klasse ausstatten, gut zu Ihnen. Wenn Sie dieses Mitglied von A in B geändert haben, müssen Sie die Methode, die ein A zurückgibt, neu schreiben. Offensichtlich muss nun eine Methode erstellt und mit verfügbaren Daten gefüllt werden, anstatt nur ein einziger Zeilenumbruch ein Mitglied. Die Schnittstelle Ihrer Klasse wäre unverändert.
quelle