No novo pacote java.time, as classes principais estão usando o método factory em of
vez de um construtor público. Mesmo gostando dos cosméticos do of
método, não vejo uma boa razão para não usar um construtor. A documentação que encontrei explica apenas que esse é o caso e não explica exatamente o motivo.
Citação do tutorial :
A maioria das classes na API Date-Time cria objetos imutáveis, o que significa que, após a criação do objeto, ele não pode ser modificado. Para alterar o valor de um objeto imutável, um novo objeto deve ser construído como uma cópia modificada do original. Isso também significa que a API Date-Time é, por definição, segura para threads. Isso afeta a API, pois a maioria dos métodos usados para criar objetos de data ou hora são prefixados com de, de ou com, em vez de construtores, e não há métodos definidos.
Nem sempre é necessário criar um novo objeto ao obter um valor de um tipo imutável. Um método de fábrica pode retornar um objeto que já foi criado enquanto uma chamada de construtor sempre cria um novo objeto.
Existem outras vantagens nos métodos de fábrica, mas eles não estão tão intimamente relacionados à imutabilidade quanto à API Date-Time. Por exemplo, os métodos de fábrica têm nomes e podem retornar objetos de algum subtipo.
fonte
Não projetei ou escrevi a API de data e hora do Java, por isso não posso dizer definitivamente "por que eles fizeram dessa maneira". No entanto, posso sugerir dois motivos principais para que eles façam dessa maneira:
Primeiro, considere o contexto: o código de datas e hora do Java é um pacote grande e complexo que trata de um assunto muito complicado. Por mais comum que seja a "hora", a implementação do conceito envolve dezenas de interpretações e formatos, com variações entre locais geográficos (fusos horários), idiomas, sistemas de calendário, resoluções de relógio, escalas de tempo, escalas de tempo, representações numéricas, fontes de dados e intervalos. Deltas corretivos (por exemplo, anos bissextos / dias) são comuns e podem ser inseridos irregularmente a qualquer momento (segundos bissextos). No entanto, o pacote é um recurso essencial, provavelmente usado amplamente, e espera-se que ele lide com todas essas variações de maneira correta e precisa. É uma tarefa difícil. O resultado, sem surpresa, é uma API complexa, incluindo muitas classes, cada uma com muitos métodos.
Agora, por que usar
of
métodos em vez de um construtor de classe "regular"? Por exemplo , por queLocalDate.of(...)
,LocalDate.ofEpochDay(...)
eLocalDate.ofYearDay(...)
não apenas um punhado denew LocalDate(...)
chamadas?Primeiro, poder expressivo : métodos nomeados individuais expressam a intenção da construção e a forma dos dados que estão sendo consumidos.
Suponha por um momento que a sobrecarga do método Java seja suficiente para permitir a variedade de construtores que você deseja. (Sem entrar em uma discussão sobre o recurso de linguagem sobre digitação de patos e envio único versus dinâmico versus envio múltiplo , vou apenas dizer: às vezes isso é verdade, às vezes não. Por enquanto, apenas assuma que não há nenhuma limitação técnica.)
Pode ser possível para a documentação do construtor declarar "quando passado apenas um único
long
valor, esse valor é interpretado como uma contagem de dias da época, não um ano". Se os tipos de dados de baixo nível passados para os outros construtores forem diferentes (por exemplo, apenas o caso da época usalong
e todos os outros construtores usamint
), você pode se safar disso.Se você analisasse o código que chama um
LocalDate
construtor com um únicolong
, seria muito semelhante ao código no qual um ano é passado, especialmente com a passagem de um ano, sem dúvida o caso mais comum. Ter esse construtor comum pode ser possível, mas não necessariamente leva a uma grande clareza.A API explicitamente chamando no
ofEpochDay
entanto, sinaliza uma clara diferença de unidades e intenção. Da mesma forma,LocalDate.ofYearDay
sinaliza que omonth
parâmetro comum está sendo ignorado e que o parâmetro day, embora aindaint
seja um,dayOfYear
não é umdayOfMonth
. Os métodos explícitos do construtor visam expressar o que está acontecendo com maior clareza.Linguagens dinamicamente e tipadas como pato, como Python e JavaScript, têm outros meios para sinalizar interpretações alternativas (por exemplo, parâmetros opcionais e valores de sentinela fora da banda ), mas mesmo os desenvolvedores de Python e JS costumam usar nomes de métodos distintos para sinalizar interpretações diferentes. É ainda mais comum em Java, dadas as restrições técnicas (é uma linguagem de envio único estaticamente) e as convenções / expressões culturais.
Segunda forma paralela .
LocalDate
poderia fornecer um construtor Java padrão, além de, ou no lugar de, seus doisof
métodos. Mas com que finalidade? Ele ainda precisaofEpochDay
eofDayYear
para esses casos de uso. Algumas classes fornecem construtores e o equivalente aofXYZ
métodos - por exemplo, ambosFloat('3.14')
eFloat.parseFloat('3.14')
existem. Mas se você precisa deofXYZ
construtores para algumas coisas, por que não usá-las o tempo todo? Isso é mais simples, mais regular e mais paralelo. Como um tipo imutável, a maioria dosLocalDate
métodos são construtores. Existem grandes grupos de sete de métodos que constroem novos casos (respectivamente, oat
,from
,minus
,of
,parse
,plus
ewith
prefixos). DosLocalDate
mais de 60 métodos, 35+ são construtores de fato . Apenas dois deles podem ser facilmente convertidos em construtores padrão baseados em classe. Realmente faz sentido, para casos especiais, aqueles 2 de uma maneira não paralela a todos os outros? O código do cliente usando esses dois construtores de casos especiais seria notavelmente mais claro ou mais simples? Provavelmente não. Pode até tornar o código do cliente mais variado e menos direto.fonte