Non ho progettato o scritto l'API Date-Time di Java, quindi non posso dire definitivamente "perché lo hanno fatto in questo modo". Posso tuttavia suggerire due motivi chiave per cui dovrebbero farlo in questo modo:
- Potere espressivo
- Modulo parallelo
Innanzitutto, considera il contesto: le date e il time code di Java sono un pacchetto ampio e complesso che si occupa di un argomento difficile molto . Comune quanto il "tempo", l'implementazione del concetto implica decine di interpretazioni e formati, con variazioni su posizioni geografiche (fusi orari), lingue, sistemi di calendario, risoluzioni di clock, scale temporali, rappresentazioni numeriche, fonti di dati e intervalli. I delta correttivi (ad esempio anni bisestili / giorni) sono comuni e possono essere inseriti in modo irregolare in qualsiasi momento (secondi bisestili). Tuttavia, il pacchetto è una caratteristica fondamentale, che probabilmente sarà ampiamente utilizzata, e ci si aspetta che affronti tutte queste variazioni in modo corretto e preciso. È un compito arduo. Il risultato, non sorprendentemente, è una API complessa che include molte classi, ognuna con molti metodi.
Ora, perché usare i metodi of
piuttosto che un costruttore di classi "normale"? Per esempio , perché LocalDate.of(...)
, LocalDate.ofEpochDay(...)
e LocalDate.ofYearDay(...)
piuttosto che solo una manciata di chiamate new LocalDate(...)
?
Primo, potere espressivo : i singoli metodi denominati esprimono l' intento della costruzione e il modulo dei dati che vengono consumati.
Supponiamo per un momento che l' sovraccarico del metodo di Java sia sufficiente per consentire la varietà di costruttori che si desidera. (Senza entrare in una discussione sulle funzionalità linguistiche in digitazione anatra e single vs. dynamic vs. dispatch multiplo Dirò solo: a volte questo è vero, a volte no. Per ora, presumi solo che non ci siano limitazioni tecniche.)
Potrebbe essere possibile che la documentazione del costruttore dichiari "quando viene passato un solo valore long
, quel valore viene interpretato come un conteggio del giorno dell'epoca, non un anno." Se i tipi di dati di basso livello passati agli altri costruttori sono diversi (ad esempio solo il caso epoch usa long
, e tutti gli altri costruttori usano int
), potresti farla franca.
Se hai guardato il codice chiamando un costruttore LocalDate
con un singolo long
, sembrerebbe molto simile al codice in cui è passato un anno, specialmente con il passare di un anno probabilmente il caso più comune. Avere quel costruttore comune potrebbe essere possibile, ma non porterebbe necessariamente a una grande chiarezza.
L'API che richiama esplicitamente ofEpochDay
tuttavia segnala una netta differenza tra unità e intento. Allo stesso modo LocalDate.ofYearDay
segnala che il parametro comune month
viene saltato e che il parametro giorno, mentre è ancora un int
, è un dayOfYear
non un dayOfMonth
. I metodi di costruzione espliciti hanno lo scopo di esprimere ciò che sta accadendo con maggiore chiarezza.
Linguaggi digitati in modo dinamico e anatra come Python e JavaScript hanno altri mezzi per segnalare interpretazioni alternative (ad es. parametri opzionali e out-of-band valori sentinella ), ma anche gli sviluppatori Python e JS utilizzano spesso nomi di metodi distinti per segnalare diverse interpretazioni. È ancora più comune in Java, dati i suoi limiti tecnici (è un linguaggio tipizzato in modo statico, a una sola uscita) e le sue convenzioni / espressioni culturali.
Secondo, modulo parallelo . LocalDate
potrebbe fornire un costruttore Java standard in aggiunta o in sostituzione dei suoi due metodi of
. Ma a quale fine? Ha ancora bisogno di ofEpochDay
e ofDayYear
per questi casi d'uso. Alcune classi forniscono entrambi i costruttori e l'equivalente dei metodi ofXYZ
; ad esempio, esistono sia Float('3.14')
che Float.parseFloat('3.14')
. Ma se hai bisogno di ofXYZ
di costruttori per alcune cose, perché non usarli tutto il tempo? È più semplice, più regolare e più parallelo. Come tipo immutabile, i maggioranza di LocalDate
metodi sono costruttori. Esistono sette principali gruppi di metodi che costruiscono nuove istanze (rispettivamente, at
, from
, minus
, of
, parse
, plus
e with
prefissi). Dei metodi 60+ di LocalDate
, 35+ sono costruttori di fatto . Solo 2 di questi potrebbero essere facilmente convertiti in costruttori basati su classi standard. Ha davvero senso, in casi speciali, quei 2 in un modo non parallelo a tutti gli altri? Il codice client che utilizza questi due casi speciali sarà notevolmente più chiaro o più semplice? Probabilmente no. Potrebbe persino rendere il codice client più vario e meno diretto.