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:
- Ausdruckskraft
- Parallele Form
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 , warum LocalDate.of(...)
, LocalDate.ofEpochDay(...)
und LocalDate.ofYearDay(...)
nicht nur eine Handvoll new 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 Epochenfall long
und alle anderen Konstruktoren int
), können Sie damit durchkommen.
Wenn Sie sich Code ansehen , der einen LocalDate
Konstruktor mit einem einzelnen aufruft long
, 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 wird LocalDate.ofYearDay
signalisiert, dass der allgemeine month
Parameter übersprungen wird und dass der Tagesparameter, obwohl er noch ein int
ist, dayOfYear
kein a ist dayOfMonth
. 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 beiden of
Methoden einen Standard-Java-Konstruktor bereitstellen . Aber zu welchem Zweck? Es braucht noch ofEpochDay
und ofDayYear
für diese Anwendungsfälle. Einige Klassen bieten sowohl Konstruktoren als auch das Äquivalent von ofXYZ
Methoden - zum Beispiel beide Float('3.14')
und Float.parseFloat('3.14')
existieren. Aber wenn Sie ofXYZ
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 der LocalDate
sind Methoden Bauer. Es gibt sieben Hauptgruppen von Methoden , dass Konstrukt neue Instanzen (bzw. die at
, from
, minus
, of
, parse
,plus
und with
Präfixe). Von LocalDate
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.