Im neuen Paket java.time verwenden die Kernklassen die Factory-Methode of
anstelle eines öffentlichen Konstruktors. Obwohl ich die Kosmetik der of
Methode mag, sehe ich keinen guten Grund, keinen Konstruktor zu verwenden. Die Dokumentation, die ich gefunden habe, erklärt nur, dass dies der Fall ist und geht nicht wirklich darauf ein, warum dies der Fall ist.
Zitat aus dem Tutorial :
Die meisten Klassen in der Datums- / Uhrzeit-API erstellen Objekte, die unveränderlich sind. Dies bedeutet, dass das Objekt nach dem Erstellen nicht mehr geändert werden kann. Um den Wert eines unveränderlichen Objekts zu ändern, muss ein neues Objekt als modifizierte Kopie des Originals erstellt werden. Dies bedeutet auch, dass die Datums- / Uhrzeit-API per Definition threadsicher ist. Dies wirkt sich insofern auf die API aus, als den meisten Methoden zum Erstellen von Datums- oder Zeitobjekten ein Präfix von, von oder mit anstelle von Konstruktoren vorangestellt wird und keine festgelegten Methoden vorhanden sind.
Es ist nicht immer erforderlich, ein neues Objekt zu erstellen, wenn Sie einen Wert eines unveränderlichen Typs erhalten. Eine Factory-Methode kann ein Objekt zurückgeben, das bereits erstellt wurde, während ein Konstruktoraufruf immer ein neues Objekt erstellt.
Factory-Methoden bieten einige andere Vorteile, die jedoch nicht so eng mit der Unveränderlichkeit und der Datums- / Uhrzeit-API zusammenhängen. Factory-Methoden haben beispielsweise Namen und können Objekte eines bestimmten Subtyps zurückgeben.
quelle
Ich habe die Datums- / Uhrzeit-API von Java nicht entworfen oder geschrieben, daher kann ich nicht definitiv sagen, warum sie das so gemacht haben. Ich kann jedoch zwei Hauptgründe vorschlagen, warum sie dies so tun sollten:
Betrachten Sie zunächst den Kontext: Javas Datums- und Zeitcode ist ein großes, komplexes Paket, das sich mit einem sehr kniffligen Thema befasst. So häufig "Zeit" auch ist, die Implementierung des Konzepts umfasst Dutzende von Interpretationen und Formaten mit Variationen über geografische Standorte (Zeitzonen), Sprachen, Kalendersysteme, Uhrauflösungen, Zeitskalen, numerische Darstellungen, Datenquellen und Intervalle. Korrekturdeltas (z. B. Schaltjahre / -tage) sind häufig und können jederzeit unregelmäßig eingefügt werden (Schaltsekunden). Das Paket ist jedoch eine Kernfunktion, die wahrscheinlich weit verbreitet ist, und es wird erwartet, dass alle diese Variationen sowohl korrekt als auch präzise behandelt werden. Es ist eine große Aufgabe. Das Ergebnis ist nicht überraschend eine komplexe API mit vielen Klassen mit jeweils vielen Methoden.
Warum sollten Sie
of
Methoden anstelle eines "normalen" Klassenkonstruktors verwenden? Zum Beispiel , warumLocalDate.of(...)
,LocalDate.ofEpochDay(...)
undLocalDate.ofYearDay(...)
nicht nur eine Handvollnew LocalDate(...)
Anruf?Erstens Ausdruckskraft : Einzelne benannte Methoden drücken die Absicht der Konstruktion und die Form der verbrauchten Daten aus.
Nehmen Sie für einen Moment an, dass die Überladung der Java- Methode ausreicht, um die gewünschte Vielfalt an Konstruktoren zuzulassen. (Ohne auf eine sprachliche Diskussion über Ententypisierung und Einzel- oder Dynamikversuche im Vergleich zu Mehrfachversand einzugehen, sage ich nur: Manchmal ist dies wahr, manchmal nicht. Nehmen wir vorerst nur an, dass es keine technischen Einschränkungen gibt.)
In der Konstruktordokumentation kann möglicherweise
long
angegeben werden, dass "wenn nur ein einziger Wert übergeben wird, dieser Wert als Anzahl der Epochentage und nicht als Jahr interpretiert wird". Wenn die an die anderen Konstruktoren übergebenen Datentypen auf niedriger Ebene unterschiedlich sind (z. B. nur der Epochenfalllong
und alle anderen Konstruktorenint
), können Sie damit durchkommen.Wenn Sie sich Code ansehen , der einen
LocalDate
Konstruktor mit einem einzelnen aufruftlong
, sieht er dem Code sehr ähnlich, in dem ein Jahr übergeben wird, insbesondere wenn ein Jahr wahrscheinlich der häufigste Fall ist. Es könnte möglich sein, diesen gemeinsamen Konstruktor zu haben, aber dies würde nicht unbedingt zu großer Klarheit führen.Die API, die explizit aufruft
ofEpochDay
, signalisiert jedoch einen deutlichen Unterschied in Einheiten und Absichten. In ähnlicher Weise wirdLocalDate.ofYearDay
signalisiert, dass der allgemeinemonth
Parameter übersprungen wird und dass der Tagesparameter, obwohl er noch einint
ist,dayOfYear
kein a istdayOfMonth
. Explizite Konstruktormethoden sollen die Vorgänge klarer ausdrücken.Dynamisch und ententypisierte Sprachen wie Python und JavaScript haben andere Mittel, um alternative Interpretationen zu signalisieren (z. B. optionale Parameter und Out-of-Band- Sentinel-Werte ), aber selbst Python- und JS-Entwickler verwenden häufig unterschiedliche Methodennamen, um unterschiedliche Interpretationen zu signalisieren. Es ist in Java aufgrund seiner technischen Einschränkungen (es ist eine statisch typisierte Single-Dispatch-Sprache) und seiner kulturellen Konventionen / Redewendungen noch häufiger.
Zweitens parallele Form .
LocalDate
könnte zusätzlich zu oder anstelle seiner beidenof
Methoden einen Standard-Java-Konstruktor bereitstellen . Aber zu welchem Zweck? Es braucht nochofEpochDay
undofDayYear
für diese Anwendungsfälle. Einige Klassen bieten sowohl Konstruktoren als auch das Äquivalent vonofXYZ
Methoden - zum Beispiel beideFloat('3.14')
undFloat.parseFloat('3.14')
existieren. Aber wenn SieofXYZ
für einige Dinge Konstruktoren benötigen , warum nicht diese ständig verwenden? Das ist einfacher, regelmäßiger und paralleler. Als unveränderliche Art, die Mehrheit derLocalDate
sind Methoden Bauer. Es gibt sieben Hauptgruppen von Methoden , dass Konstrukt neue Instanzen (bzw. dieat
,from
,minus
,of
,parse
,plus
undwith
Präfixe). VonLocalDate
den über 60 Methoden sind 35 de facto Konstruktoren. Nur zwei davon konnten problemlos in klassenbasierte Standardkonstruktoren konvertiert werden. Ist es wirklich sinnvoll, diese 2 auf eine Weise zu spezialisieren, die nicht parallel zu allen anderen ist? Wäre Client-Code mit diesen beiden Sonderfallkonstruktoren deutlich klarer oder einfacher? Wahrscheinlich nicht. Dies könnte den Client-Code sogar vielfältiger und unkomplizierter machen.quelle