Gibt es tatsächlich Nachteile bei der Verkettung selbstreferenzieller Methoden?

14

Ich habe kürzlich vorgeschlagen, eine Verkettungsmethode für eine bestimmte Klasse in einem bestimmten Projekt zu implementieren, damit die Lesbarkeit des Codes verbessert werden kann. Ich bekam eine "fließende Schnittstelle sollte nicht nur aus Bequemlichkeitsgründen, sondern auch aus semantischen Gründen implementiert werden" Antwort und ließ meinen Vorschlag abschneiden. Ich antwortete, dass ich keine fließende Benutzeroberfläche vorschlage, sondern die Verkettung der Methoden selbst (beide können miteinander verwechselt werden, siehe unten), um die Lesbarkeit und den Codierungskomfort zu verbessern. Der Vorschlag wurde erneut abgeschnitten.

Wie auch immer, das brachte mich auf den Gedanken, dass ich möglicherweise in eine schlechte Praxis verwickelt sein könnte, indem ich immer "dies" in Methoden zurückgebe, die nichts zurückgeben sollen (z. B. Setter).

Meine Frage ist: Kann die Anwendung der vorherigen Konvention als schlechte Praxis oder Missbrauch angesehen werden? Warum? Ich glaube nicht, dass es irgendwelche Leistungsmängel gibt, oder?

dukeofgaming
quelle
2
Schauen Sie sich diese Frage für eine nette Diskussion an. Programmers.stackexchange.com/questions/48419/…
KeesDijk
@KeesDijk Danke, ich habe meine Frage ein wenig bearbeitet, so dass sie dieser nicht ähnlich ist, da ich mich mehr für Verkettungsmethoden aus derselben Klasse
interessiere
1
Bei SO haben sie mir gesagt, dass Verketten nichts für C ++ ist - stackoverflow.com/questions/5760551/… - woran denkst du?
kagali-san
1
@mhambra Es sieht so aus, als müssten Sie bei der Implementierung der Methodenverkettung nur vorsichtig sein und klare Standards dafür definieren.
dukeofgaming

Antworten:

10

Nein

Wie Kent Beck betont, wird Code weitaus häufiger gelesen als geschrieben.

Wenn die Methodenverkettung den Code lesbarer macht, verwenden Sie die Methodenverkettung.

Steven A. Lowe
quelle
1
Tolles Buch. +1
Rein Henrichs
5
ABER , was ist, wenn Sie die einzige Methode sind, die lesbarer verkettet? Wenn dies eine Frage der Systematik ist, müssen Sie sich an eine Reihe von Kodierungskonventionen halten: Dies bedeutet, dass Sie aus Gründen der Konsistenz in der gleichen Weise wie der vorhandene Code schreiben müssen.
Coredump
@coredump Es hört sich so an, als ob den OPs bereits befohlen wurde, dies zu tun, aber ich denke, Steven hat dies nur gesagt, wenn die Methodenverkettung es lesbarer macht.
Panzercrisis
1
@Panzercrisis OPs wurde aus Bequemlichkeits- und Semantikgründen angewiesen, auf die Verkettung von Methoden zu verzichten. Stevens Antwort lautet im Grunde genommen "Mach es trotzdem" und berücksichtige nur die Lesbarkeit des OP-Codes für sich, ohne die Meinung oder Konsistenz des Teams zu berücksichtigen. Was ist, wenn OP jede vorhandene Klasse im Projekt so umschreiben möchte, dass sie hinsichtlich der Lesbarkeit des Codes seinem Geschmack entspricht? So verstehe ich das Convenience / Semantics-Argument: Es sollte einen "technischen" Grund für die Verkettung von Methoden geben (übrigens klingt dieses Argument auch so, als würde sich die andere Person eine Ausrede für ihre eigenen Vorlieben
ausdenken
9

Ja, es gibt Nachteile

Einfach zu lesender Code ist gut, aber achten Sie auch darauf, was der Code mitteilt . Wenn die Methoden eines Objekts immer das Objekt zurückgeben, werden einige Dinge kommuniziert:

  1. Ich benötige eine erweiterte Konfiguration, bei der nicht unbedingt ersichtlich ist, in welcher Reihenfolge die Dinge eingestellt oder konfiguriert werden sollen
  2. Jeder nachfolgende Methodenaufruf baut auf dem letzten auf

Gültiger Anwendungsfall: Ad-hoc-Datenbankabfragen

Klassenbibliotheken gibt es in fast jeder Sprache, mit denen Sie eine Datenbank abfragen können, ohne auf fest codiertes SQL zurückgreifen zu müssen. Nehmen Sie das Entity Framework für .NET als Beispiel:

DBContext db = new DBContext();
List<Post> posts = db.Posts
    .Where(post => post.Title.Contains("Test"))
    .OrderBy(post => post.DateCreated)
    .ToList();

Dies ist eine flüssige Schnittstelle, bei der jeder nachfolgende Methodenaufruf auf der vorherigen aufbaut. Das logische Lesen dieser Aufrufe ist im Zusammenhang mit der Abfrage einer Datenbank sinnvoll.

Ungültiger Anwendungsfall: Syntaktischer Zucker zum Festlegen von Eigenschaften

Verwenden wir nun dasselbe Muster für die PostKlasse:

public class Post
{
    public string Title { get; set; }
    public DateTime DateCreated { get; set; }
    public string Body { get; set; }

    public Post SetTitle(string title)
    {
        Title = title;

        return this;
    }

    public Post SetDateCreated(DateTime created)
    {
        DateCreated = created;

        return this;
    }

    public Post SetBody(string body)
    {
        Body = body;

        return this;
    }
}

Schauen wir uns nun an, wie Sie diese Klasse verwenden würden:

Post post = new Post()
    .SetTitle("Test")
    .SetDateCreated(DateTime.Now)
    .SetBody("Just a test");

Wenn ich diesen Code sehe, stelle ich sofort folgende Frage: "Wird SetBodydie Datenbank nach dem Aufruf abgefragt? Muss ich eine andere Methode aufrufen, um zu sagen, dass ich fertig bin?"

Was kommunizieren die verketteten Methodenaufrufe über die PostKlasse mit dem Code ?

  1. Ich habe ein kompliziertes Setup
  2. Jeder Methodenaufruf baut auf dem vorherigen auf

Ist das tatsächlich wahr? Nein. Die PostKlasse ist nicht kompliziert aufgebaut. Das Festlegen von Titel, Erstellungsdatum und Text baut nicht auf einem komplizierteren Endziel auf. Sie haben einen quadratischen Stift in ein rundes Loch gestampft.

Der Nachteil der selbstreferenziellen Methodenverkettung besteht darin, dass Sie mitteilen, dass mehrere Methodenaufrufe erforderlich sind, um etwas zu tun, und dass jeder Aufruf den letzten aufbaut. Wenn dies nicht zutrifft, kann die Verkettung von Methoden dazu führen, dass anderen Programmierern das Falsche mitgeteilt wird.

Als Ihre Mitarbeiter sagten:

Fließende Schnittstellen sollten nicht nur zur Vereinfachung, sondern auch zur Semantik implementiert werden

Sie waren absolut korrekt. Eine flüssige Schnittstelle oder Methodenverkettung kommuniziert etwas an und für sich, was möglicherweise nicht wahr ist.

Greg Burghardt
quelle
Dies setzt voraus, dass Methodenverkettung und komplexe Konfiguration immer Hand in Hand gehen. Sie sind verschiedene Einheiten und die Anwesenheit einer sollte Sie nicht dazu bringen, die andere anzunehmen.
Jack
Es ist nicht nur "komplexe Konfiguration", sondern auch "nachfolgende Methodenaufrufe bauen auf der vorherigen auf". Methodenverkettung enthält eine Metakommunikation, die nicht immer dem Zweck einer Klasse entspricht.
Greg Burghardt
1
Nachfolgende Methodenaufrufe, die sich aus früheren Methodenaufrufen zusammensetzen, unterscheiden sich ebenfalls von der Methodenverkettung, und ich halte es nicht für zuverlässig oder nützlich, die Syntax der Methodenverkettung als starke Kommunikation für die Semantik von auftragsabhängigen Reihen von Nebeneffektoperationen zu behandeln. Es ist eine syntaktische Abkürzung, nichts weiter. Verwenden Sie es dort, wo es die Dinge kürzer und lesbarer macht.
Jack
1
Ich verstehe, Sie denken, dass die Verkettung von Methoden getrennt ist, aber ich sage, dass andere Programmierer, die nicht in Ihrem Kopf waren und andere Klassenbibliotheken verwenden, die aus diesen Gründen die Verkettung von Methoden implementieren, möglicherweise Annahmen über Ihren Code treffen, die falsch sind. Beachten Sie, dass die Verkettung von Methoden etwas implizieren kann, das Sie als Codeautor nicht beabsichtigt haben. Klar kommunizierender Code ist ebenso wichtig wie einfach zu lesender Code. Opfere nicht eins für das andere.
Greg Burghardt
1
When an object's methods always return the object, it communicates a couple of things- Ich denke, das ist eine persönliche Meinung. Es ist schwer zu behaupten, dass jeder, der verkettete Methoden betrachtet, die gleichen Dinge annimmt.
Sam Dufel
1

Der Hauptnachteil ist ein Verlust an Klarheit. Zum Beispiel:

x.foo();
x.bar();
x.baz();

Da keine dieser Anweisungen einen Wert zurückgibt (oder ignoriert wurde), können sie nur dann nützlich sein, wenn sie Nebenwirkungen hervorrufen. Vergleichen Sie das mit:

x.foo()
 .bar()
 .baz();

Erstens ist es nicht klar, dass barund bazauf Objekte des gleichen Typs wie x, es sei denn, Sie wissen für eine Tatsache, dass xdie Klasse die einzige Klasse mit diesen Methoden ist. Auch wenn dies der Fall ist, ist es nicht klar, welche Methoden angewendet xwerden oder welche neuen Objekte.

Das Hervorheben der Teile des Codes, die Nebenwirkungen haben, ist nützlich, da Sie diese Nebenwirkungen nachverfolgen müssen, um das Programm zu beurteilen. Sie müssen den potenziellen Verlust an Klarheit gegen den potenziellen Gewinn beim Schreiben von Code abwägen, aber Sie müssen auch berücksichtigen, dass Code mehr gelesen als geschrieben wird.

Doval
quelle
0

Berücksichtigen Sie alle Stilelemente von Programmiersprachen (im Gegensatz zur handcodierten Maschinensprache) und schwächen Sie das Argument "Semantik statt Zweckmäßigkeit".

Eine ganze Menge von dem, was wir als Ingenieure tun, ist die Bequemlichkeit in Bezug auf die Semantik.

rauben
quelle