En el nuevo paquete java.time, las clases principales están utilizando el método de fábrica en of
lugar de un constructor público. Aunque me gustan los cosméticos del of
método, no puedo ver una buena razón para no usar un constructor. La documentación que he encontrado solo explica que este es el caso y realmente no explica por qué es así.
Cita del tutorial :
La mayoría de las clases en la API de fecha y hora crean objetos que son inmutables, lo que significa que, después de crear el objeto, no se puede modificar. Para alterar el valor de un objeto inmutable, se debe construir un nuevo objeto como una copia modificada del original. Esto también significa que la API de fecha y hora es, por definición, segura para subprocesos. Esto afecta a la API ya que la mayoría de los métodos utilizados para crear objetos de fecha u hora tienen el prefijo de, desde o con, en lugar de constructores, y no hay métodos establecidos.
No siempre es necesario crear un nuevo objeto al obtener un valor de tipo inmutable. Un método de fábrica puede devolver un objeto que ya se ha creado, mientras que una llamada de constructor siempre crea un nuevo objeto.
Los métodos de fábrica tienen otras ventajas, pero no están tan estrechamente relacionados con la inmutabilidad y la API de fecha y hora. Por ejemplo, los métodos de fábrica tienen nombres y pueden devolver objetos de algún subtipo.
fuente
No diseñé ni escribí la API de fecha y hora de Java, por lo que definitivamente no puedo decir "por qué lo hicieron de esta manera". Sin embargo, puedo sugerir dos razones clave por las que deberían hacerlo de esta manera:
Primero, considere el contexto: el código de fecha y hora de Java es un paquete grande y complejo que trata un tema muy complicado. Tan común como el "tiempo" es, la implementación del concepto involucra docenas de interpretaciones y formatos, con variaciones entre ubicaciones geográficas (zonas horarias), idiomas, sistemas de calendario, resoluciones de reloj, escalas de tiempo, representaciones numéricas, fuentes de datos e intervalos. Los deltas correctivos (p. Ej., Años bisiestos / días) son comunes y se pueden insertar de forma irregular en cualquier momento (segundos bisiestos). Sin embargo, el paquete es una característica central, que probablemente se utilizará ampliamente, y se espera que aborde todas esas variaciones de forma correcta y precisa. Es una tarea difícil. El resultado, no es sorprendente, es una API compleja que incluye muchas clases, cada una con muchos métodos.
Ahora, ¿por qué usar
of
métodos en lugar de un constructor de clase "regular"? Por ejemplo , ¿por quéLocalDate.of(...)
,LocalDate.ofEpochDay(...)
yLocalDate.ofYearDay(...)
en lugar de sólo un puñado denew LocalDate(...)
llamadas?Primero, el poder expresivo : los métodos con nombre individuales expresan la intención de la construcción y la forma de los datos que se consumen.
Suponga por un momento que la sobrecarga de métodos de Java es suficiente para permitir la variedad de constructores que desea. (Sin entrar en una discusión sobre las características del lenguaje sobre el tipeo de patos y el despacho simple vs. dinámico vs. múltiple , solo diré: a veces esto es cierto, a veces no. Por ahora, solo asuma que no hay limitación técnica).
Es posible que la documentación del constructor establezca "cuando se pasa un solo
long
valor, ese valor se interpreta como un recuento de días de época, no un año". Si los tipos de datos de bajo nivel pasados a los otros constructores son diferentes (por ejemplo, solo el caso de la época usalong
, y todos los otros constructores usanint
), puede salirse con la suya.Si observara el código que llama a un
LocalDate
constructor con un sololong
, se vería muy similar al código en el que se pasa un año, especialmente con pasar un año posiblemente el caso más común. Tener ese constructor común podría ser posible, pero no necesariamente conduciría a una gran claridad.ofEpochDay
Sin embargo, la API que llama explícitamente indica una clara diferencia en las unidades y la intención. Del mismo modo,LocalDate.ofYearDay
indica quemonth
se está omitiendo el parámetro común y que el parámetro del día, aunque sigue siendo unint
,dayOfYear
no es undayOfMonth
. Los métodos de construcción explícitos están destinados a expresar lo que está sucediendo con mayor claridad.Los lenguajes dinámicos y de tipo pato como Python y JavaScript tienen otros medios para señalar interpretaciones alternativas (por ejemplo, parámetros opcionales y valores centinela fuera de banda ), pero incluso los desarrolladores de Python y JS a menudo usan nombres de métodos distinguidos para señalar diferentes interpretaciones. Es aún más común en Java, debido a sus limitaciones técnicas (es un lenguaje de envío único de tipo estático) y sus convenciones / modismos culturales.
Segundo, forma paralela .
LocalDate
podría proporcionar un constructor Java estándar además de, o en lugar de, sus dosof
métodos. ¿Pero con qué fin? Todavía necesitaofEpochDay
yofDayYear
para esos casos de uso. Algunas clases proporcionan ambos constructores y el equivalente deofXYZ
métodos, por ejemplo, ambosFloat('3.14')
yFloat.parseFloat('3.14')
existen. Pero si necesitaofXYZ
constructores para algunas cosas, ¿por qué no usarlas todo el tiempo? Eso es más simple, más regular y más paralelo. Como un tipo inmutable, la mayoría de losLocalDate
métodos son constructores. Hay siete grupos principales de métodos que construyen nuevas instancias (respectivamente, laat
,from
,minus
,of
,parse
,plus
ywith
prefijos). DeLocalDate
los más de 60 métodos, más de 35 son constructores de facto . Solo 2 de ellos podrían convertirse fácilmente en constructores estándar basados en clases. ¿Realmente tiene sentido hacer un caso especial de esos 2 de una manera no paralela a todos los demás? ¿El código del cliente que usa esos dos constructores de casos especiales sería notablemente más claro o más simple? Probablemente no. Incluso podría hacer que el código del cliente sea más variado y menos directo.fuente