Ich wurde kürzlich in ein Java-Webanwendungsprojekt hineingeworfen und bin auf eine Reihe von Klassen gestoßen, die diesem Format folgen:
public class MyThingy {
private final int p1;
private final String p2;
…
public MyThingy (int p1, String p2, …) {
this.p1 = p1;
this.p2 = p2;
…
}
public static void doSomething(int p1, String p2, …) throws Throwable {
final MyThingy myThingy = new MyThingy(p1, p2, …);
myThingy.execute();
}
private void execute() throws Throwable {
//do stuff
}
}
Es scheint, dass dies mit dem folgenden Code erreicht werden könnte, der mir viel einfacher zu lesen scheint.
public class MyThingy {
public static void doSomething (int p1, String p2, …) throws Throwable {
//do stuff
}
}
Der einzig mögliche Vorteil, den ich auf die erste Weise sehen kann, ist, dass wenn Sie execute () in kleinere Teile aufteilen müssten, diese alle die Anfangsparameter gemeinsam nutzen könnten, ohne sie explizit weitergeben zu müssen. Dies kommt jedoch möglicherweise nur dem faulen Codierer zugute, da der Leser nur schwer erkennen kann, welche Methoden welche Parameter benötigen und wann die Werte möglicherweise geändert werden (ähnlich wie bei globalen Variablen).
Fehlt mir etwas? Threading, Leistung?
Edit: Ich hätte erwähnen sollen, obwohl der Konstruktor öffentlich ist, wird er nicht aufgerufen. Die einzige Verwendung ist wie folgt:
MyThingy.doSomething(p1, p2...);
Abgesehen davon, dass dies an sich für das Testen problematisch ist, sehe ich keinen Grund, die Logik von execute () nicht direkt in doSomething () zu setzen. Selbst wenn wir die statische Funktion loswerden würden, macht der Konstruktor für mich immer noch keinen Sinn. Ich denke, die Parameter sollten direkt an die Methode übergeben werden, die sie verwendet.
quelle
throws Throwable
eine schlechte Praxis, sollte es zumindestthrows Exception
oder etwas Spezifischeres sein, wenn möglich. Und da schlechte Praktiken normalerweise zusammenkommen, würde ich sagen, dass diese Codevorlage nur eine weitere schlechte Praxis ist.new(...)
+execute()
in einem Aufruf auszuführen .final
). Die statische Methode ist die einzige API im Objekt, da alle Mitglieder privat sind. In nur dem Code, den Sie geteilt haben, sehe ich keine Vorteile gegenüberexecute
einer statischen Methode, die p1, p2, ... nimmtAntworten:
Ich denke, Ihre Intuition zu diesem Thema ist richtig.
Also, solltest du es benutzen ?
In der Tat geht es nicht nur um reine "Methoden als Klassen". In normalen Klassen könnten Sie versucht sein, Felder zu erstellen, die keinen Status zwischen Aufrufen öffentlicher Methoden enthalten. Sie werden nur verwendet, um die Übergabe von Parametern zwischen privaten Methoden zu vermeiden. In der Vergangenheit habe ich versucht, dies um jeden Preis zu vermeiden, aber dann festgestellt, dass auch lange Parameterlisten scheiße sind.
Ich versuche, reine "Methodenklassen" zu vermeiden, da ich denke, dass sie mit viel mentalem Gepäck verbunden sind (so viel potenzielles Potenzial). (Ich lehne mich auch an Einwegfelder in regulären Klassen.) Aber wenn es eine Menge Variablen gibt, die weitergegeben werden müssen, kann sich der Gewinn an Code-Sauberkeit lohnen.
Ich versuche, Klassen zu verwenden, wenn es einen Sinn gibt, und tatsächlich ist es normalerweise leicht, sich einen vorzustellen. Vielleicht erweitern Sie die Klasse in Zukunft um zusätzliche Implementierungen. Möglicherweise kann die Instanz als Funktionsobjekt betrachtet werden, das Sie initialisieren und weitergeben möchten. Und dann ist die Klasse keine Pseudo-OO- "Methodenklasse" mehr.
quelle
Die zusätzliche Indirektion durch den statischen Methodenaufruf trennt die Bedenken, wie ein Objekt erstellt wird, von dem Code, der das Objekt verwendet. Was Sie hier haben, ist einer einfachen Factory-Methode sehr ähnlich (es gibt das Objekt nicht zurück, aber die Indirektion der Objekterstellung ist dieselbe).
Dies kann nützlich sein, wenn Sie den Typ des erstellten Objekts steuern müssen. In diesem einfachen Beispiel muss keine Entscheidung getroffen werden, aber es wäre einfach, diese Logik hinzuzufügen.
Für Anrufer bedeutet der statische Code: "Ich muss etwas mit diesem Status tun, weiß aber nicht, wie ich delegieren soll." Die statische Methode kann dann basierend auf dem bereitgestellten Objekt an die richtige Implementierung delegieren.
Möglicherweise wird beim Ausführen eines Komponententests ein Scheinobjekt verwendet. Möglicherweise könnte basierend auf den Parametern ein anderes Objekt ausgetauscht werden, das einen anderen Algorithmus implementiert, um alles zu tun, was es tun muss. Durch Lokalisieren dieses Codes an einem Ort kann die Entscheidung an einem Ort getroffen werden und nicht an beliebig vielen.
Angesichts des Wortlauts Ihrer Frage und der Tatsache, dass bei den statischen Methoden keine Konstruktionsentscheidung getroffen wird, habe ich das Gefühl, dass dies möglicherweise nur ein Fall von Überentwicklung ist. Der meiste Code muss nicht an eine Factory delegiert werden. Die Tatsache , dass Sie Code halten Begegnung dieses wie das macht nicht alle Entscheidungen treffen , wie ich eine statische Factory-Methode wie mir sagt , zu tun erwarten würde jemand lesen Sie die GoF Buch und lief Amok.
quelle
Nun, wenn Ihr zweites Beispiel (das den vollständigen Code zeigt) so aussieht:
dann brauchen Sie noch den Konstruktor
was wiederum setzt
und jetzt bist du wieder da, wo du angefangen hast.
Sie können natürlich auch den Konstruktor eliminieren und stattdessen Getter und Setter verwenden
... aber dies erschwert Ihren statischen Methodenaufruf, da Sie jetzt mehrere Codezeilen benötigen, um die Setter zuerst aufzurufen, bevor Sie Ihre statische Methode aufrufen, wobei eine einzelne Zeile, die den Konstruktoraufruf verwendet, ausgereicht hätte.
Dies funktioniert natürlich nur, wenn Ihre Mitgliedsvariablen dies nicht sind
final
. Daher benötigen Sie immer noch den Konstruktor.quelle
final
Variable zu haben. Es kann nur einmal initialisiert werden.Normalerweise verfügt eine Klasse über viele Instanzmethoden. Sobald das Objekt erstellt wurde, kann die Implementierung von execute alle diese Instanzmethoden nutzen. Wenn Sie sich weigern, ein Objekt zu erstellen, sind alle diese Instanzmethoden nutzlos.
quelle
execute
. Also fragen, warum nicht das Ganze inline.