Die Implementierung der Verkettung in Beans ist sehr praktisch: Konstruktoren, Megakonstruktoren und Fabriken müssen nicht überladen werden, und die Lesbarkeit wird erhöht. Ich kann mir keine Nachteile vorstellen, es sei denn, Sie möchten, dass Ihr Objekt unveränderlich ist. In diesem Fall würde es sowieso keine Setter haben. Gibt es einen Grund, warum dies keine OOP-Konvention ist?
public class DTO {
private String foo;
private String bar;
public String getFoo() {
return foo;
}
public String getBar() {
return bar;
}
public DTO setFoo(String foo) {
this.foo = foo;
return this;
}
public DTO setBar(String bar) {
this.bar = bar;
return this;
}
}
//...//
DTO dto = new DTO().setFoo("foo").setBar("bar");
myCustomDTO = DTOBuilder.defaultDTO().withFoo("foo").withBar("bar").Build();
Ich würde das tun, um nicht der allgemeinen Vorstellung zu widersprechen, dass Setter leere Stellen sind.new Foo().setBar('bar').setBaz('baz')
sich das sehr "flüssig" anfühlt. Ich meine, sicher, es könnte genauso implementiert werden, aber ich würde sehr erwarten, dass ich etwas Ähnliches wieFoo().barsThe('bar').withThe('baz').andQuuxes('the quux')
Antworten:
Meine beste Vermutung: weil es CQS verletzt
Sie haben einen Befehl (Ändern des Status des Objekts) und eine Abfrage (Zurückgeben einer Kopie des Status - in diesem Fall des Objekts selbst) in derselben Methode gemischt. Das ist nicht unbedingt ein Problem, verstößt aber gegen einige der grundlegenden Richtlinien.
In C ++ ist std :: stack :: pop () beispielsweise ein Befehl, der void zurückgibt, und std :: stack :: top () ist eine Abfrage, die einen Verweis auf das oberste Element im Stapel zurückgibt. Klassischerweise möchten Sie beide kombinieren, aber Sie können das nicht und sind ausnahmesicher. (Kein Problem in Java, da der Zuweisungsoperator in Java nicht auslöst).
Wenn DTO ein Wertetyp wäre, könnten Sie mit ein ähnliches Ziel erreichen
Außerdem ist die Verkettung von Rückgabewerten ein gewaltiger Schmerz, wenn Sie sich mit Vererbung befassen. Siehe "Seltsamerweise wiederkehrendes Vorlagenmuster"
Schließlich gibt es das Problem, dass der Standardkonstruktor Sie mit einem Objekt belassen sollte, das sich in einem gültigen Zustand befindet. Wenn Sie müssen eine Reihe von Befehlen führen Sie das Objekt in einen gültigen Zustand wieder herzustellen, hat etwas sehr falsch gegangen.
quelle
abstract
T getSelf()
Methode hinzu, die den generischen Typ zurückgibt. Anstattthis
von Ihren Setzern zurückzukehren, machen Siereturn getSelf()
und dann jede übergeordnete Klasse den Typ einfach generisch und kehrenthis
von zurückgetSelf
. Auf diese Weise geben die Setter den tatsächlichen Typ und nicht den deklarierenden Typ zurück.Das Speichern einiger Tastenanschläge ist nicht zwingend. Es mag nett sein, aber bei OOP-Konventionen geht es mehr um Konzepte und Strukturen als um Tastenanschläge.
Der Rückgabewert ist bedeutungslos.
Der Rückgabewert ist nicht nur bedeutungslos, sondern auch irreführend, da Benutzer möglicherweise erwarten, dass der Rückgabewert eine Bedeutung hat. Sie können erwarten, dass es ein "unveränderlicher Setter" ist
In Wirklichkeit mutiert Ihr Setter das Objekt.
Es funktioniert nicht gut mit Vererbung.
ich kann schreiben
aber nicht
Für mich sind # 1 bis # 3 die wichtigsten. Bei gut geschriebenem Code geht es nicht um angenehm angeordneten Text. In gut geschriebenem Code geht es um die grundlegenden Konzepte, Beziehungen und Strukturen. Text spiegelt nur die wahre Bedeutung des Codes nach außen wider.
quelle
public class Foo<T extends Foo> {...}
Wenn der Setter zurückkehrtFoo<T>
. Auch diese "Setter" -Methoden, ich ziehe es vor, sie "mit" -Methoden aufzurufen. Wenn Überladung gut funktioniert, dann ebenFoo<T> with(Bar b) {...}
, sonstFoo<T> withBar(Bar b)
.Ich denke nicht, dass dies eine OOP-Konvention ist, sie hängt mehr mit dem Sprachdesign und seinen Konventionen zusammen.
Anscheinend möchten Sie Java verwenden. Java hat eine JavaBeans- Spezifikation, die den Rückgabetyp des Setters angibt, der ungültig sein soll, dh er steht in Konflikt mit der Verkettung von Settern. Diese Spezifikation wird allgemein akzeptiert und in einer Vielzahl von Tools implementiert.
Natürlich könnte man fragen, warum nicht ein Teil der Spezifikation verkettet wird. Ich kenne die Antwort nicht, vielleicht war dieses Muster zu dieser Zeit einfach nicht bekannt / beliebt.
quelle
Object
, wird möglicherweise das Singleton des TypsVoid
zurückgegeben, wenn die Methodevoid
den Rückgabetyp angibt. In anderen Nachrichten ist das "Hinterlassen eines Kommentars, aber nicht das Abstimmen" anscheinend ein Grund dafür, dass eine Prüfung nach dem ersten Post nicht bestanden wird, auch wenn es sich um einen guten Kommentar handelt. Ich beschuldige Shog dafür.Wie andere Leute gesagt haben, wird dies oft als flüssige Schnittstelle bezeichnet .
Normalerweise sind Setter Call-Passing- Variablen als Antwort auf den Logikcode in einer Anwendung. Ihre DTO-Klasse ist ein Beispiel dafür. Herkömmlicher Code, wenn Setter nichts zurückgeben, ist hierfür am besten geeignet. Andere Antworten haben übrigens erklärt.
Es gibt jedoch einige Fälle, in denen eine flüssige Benutzeroberfläche eine gute Lösung sein kann, die alle gemeinsam haben.
Einrichten der Konfiguration, z. B. Fluent-Nhibernate
Einrichten von Testdaten in Komponententests mit speziellen TestDataBulderClasses (Object Mothers)
Das Erstellen einer guten, fließenden Benutzeroberfläche ist jedoch sehr schwierig . Daher lohnt es sich nur, wenn Sie über viele „statische“ Einstellungen verfügen. Auch fließende Benutzeroberflächen sollten nicht mit „normalen“ Klassen gemischt werden. Daher wird häufig das Builder-Muster verwendet.
quelle
Ich denke, der Hauptgrund, warum es keine Konvention ist, einen Setter nach dem anderen zu verketten, liegt darin, dass in diesen Fällen ein Optionsobjekt oder Parameter in einem Konstruktor typischer ist. C # hat auch eine Initialisierungssyntax.
Anstatt von:
Man könnte schreiben:
(in JS)
(in C #)
(in Java)
setFoo
undsetBar
werden dann nicht mehr zur Initialisierung benötigt und können später zur Mutation verwendet werden.Die Verkettbarkeit ist unter bestimmten Umständen hilfreich, es ist jedoch wichtig, nicht zu versuchen, alles in eine einzelne Zeile zu packen, nur um die Anzahl der Zeilenumbrüche zu verringern.
Zum Beispiel
erschwert das Lesen und Verstehen des Geschehens. Neuformatierung zu:
Ist viel einfacher zu verstehen und macht den "Fehler" in der ersten Version offensichtlicher. Sobald Sie den Code in dieses Format überarbeitet haben, gibt es keinen wirklichen Vorteil mehr gegenüber:
quelle
/
zu Zeilenumbruch darstellt]With Foo(1234) / .x = 23 / .y = 47
wäre gleichbedeutend mitDim temp=Foo(1234) / temp.x = 23 / temp.y = 47
. Eine solche Syntax Erstellen von nicht Mehrdeutigkeit da.x
von selbst umgibt „Mit“ Aussage keine andere Bedeutung als zu binden an die sofort haben können [wenn es keinen gibt, oder das Objekt dort kein Mitglied hatx
, dann.x
ist bedeutungslos]. Oracle hat so etwas nicht in Java aufgenommen, aber ein solches Konstrukt würde problemlos in die Sprache passen.Diese Technik wird tatsächlich im Builder-Muster verwendet.
Im Allgemeinen wird dies jedoch vermieden, da es nicht eindeutig ist. Es ist nicht offensichtlich, ob der Rückgabewert das Objekt ist (so dass Sie andere Setter aufrufen können) oder ob das Rückgabeobjekt der Wert ist, der gerade zugewiesen wurde (auch ein gemeinsames Muster). Dementsprechend schlägt das Prinzip der geringsten Überraschung vor, dass Sie nicht versuchen sollten, anzunehmen, dass der Benutzer die eine oder andere Lösung sehen möchte, es sei denn, dies ist grundlegend für das Design des Objekts.
quelle
Obj* x = doSomethingToObjAndReturnIt(new Obj(1, 2, 3));
mir einfällt, ist, dass es meiner Meinung nach auch an Popularität gewonnen hat, weil es sich spiegelta = b = c = d
, obwohl ich nicht überzeugt bin, dass Popularität begründet war. Ich habe in einigen atomaren Operationsbibliotheken die von Ihnen erwähnte gesehen, die den vorherigen Wert zurückgibt. Moral der Geschichte? Es ist noch verwirrender, als ich es klingen ließ =)new BetterText(string).indent(4).box().print();
. In diesem Fall habe ich einen Haufen Gobbledygook umgangen und eine Zeichenfolge genommen, eingerückt, verpackt und ausgegeben. Möglicherweise möchten Sie sogar eine Duplizierungsmethode innerhalb der Kaskade (z. B..copy()
), damit alle folgenden Aktionen das Original nicht mehr ändern.Dies ist eher ein Kommentar als eine Antwort, aber ich kann keinen Kommentar abgeben, also ...
Ich wollte nur erwähnen, dass mich diese Frage überrascht hat, weil ich das überhaupt nicht als ungewöhnlich betrachte . Eigentlich ist in meinem Arbeitsumfeld (Webentwickler) sehr sehr verbreitet.
Dies ist zum Beispiel die Doktrin von Symfony: generate: entity-Befehl , der standardmäßig alle automatisch generiert .
setters
jQuery verkettet die meisten seiner Methoden auf ähnliche Weise.
quelle
JAB
. In meiner Studienzeit habe ich bei JS nach unten zu schauen als ein Gräuel Möchtegern-Skriptsprache, aber nach ein paar Jahren mit ihm zu arbeiten, und das Erlernen der RECHTS Weg , es zu verwenden, habe ich komme zu ... wirklich lieben es . Und ich denke, dass es mit ES6 eine wirklich ausgereifte Sprache wird. Aber was mich dazu bringt, den Kopf zu drehen, ist ... was hat meine Antwort überhaupt mit JS zu tun? ^^ U