Devo carregar os dados do meu objeto Java em construção, ou explicitamente através de uma chamada de método?
-
19-09-2019 - |
Pergunta
Esta é uma questão de design. Eu estou tentando decidir entre 2 implementações.
A fim de explicar adequadamente esse eu precisar de um exemplo. Assim, por uma questão de exemplo:
Eu tenho uma classe que gera um relatório sobre, digamos, certos valores do mercado de ações em um dia específico. Eu criar um objeto StockMarketReportGenerator
, passando a data de hoje, e gera um relatório com base em valores de mercado de hoje.
O StockMarketReportGenerator
"tem um" objeto StockMarketData
. A finalidade do objeto StockMarketData
é conter todos os valores do mercado de ações que são armazenadas em uma tabela (provavelmente chamado StockMarket :)) no banco de dados, e alguns outros valores calculados a partir dos dados da tabela. Ele tem métodos privados que se conectam com o banco de dados, recuperar os dados, fazer os cálculos necessários, e armazenar os valores finais em variáveis ??de membro do objeto. (Em seguida, ele tem métodos getter para expor esses valores, mas há métodos setter.) A classe StockMarketData
é basicamente um "titular" para valores de dados do mercado de ações. Eu tenho uma função central chamado algo como "calculateStockMarketData()
" que chama todos esses métodos auxiliares privadas e configura o objeto. (Estou ciente de que toda esta transformação poderia realmente ser mais facilmente manipulados por um quadro como o Hibernate;. Mas a decisão foi tomada para fazê-lo manualmente, pois é um projeto muito pequeno, um pouco temporária e não vale o setup)
A minha pergunta é esta - de minha classe ReportGenerator
, eu só preciso do objeto StockMarketData
para acessar suas propriedades /
variáveis ??de membro - pós-processamento e pós-cálculos. O que significa que realmente, eu quero pegar o objeto pré-cheia
com dados. E assim que eu mantenho o método calculateStockMarketData
privado e chamá-lo automaticamente a partir do StockMarketData
construtor. Mas eu estou me sentindo um pouco desconfortável em fazer toda a minha transformação em um construtor e depois não ter quaisquer métodos públicos. É este uma falha de projeto? Ou é realmente a forma mais lógica para fazer isso? Basicamente, qual dos 2 implementações seguintes é melhor?
1) (Minha implementação atual) Faça o método calculateStockMarketData()
privado central e chamá-lo a partir do construtor método StockMarketData
(passando a data de hoje), para que sempre que você tem um objeto StockMarketData
, já está cheio. Então tudo que eu precisaria da classe ReportGenerator
antes de eu começar a usar as propriedades do objeto é a linha:
StockMarketData myData = new StockMarketData(someDate);
2) Faça o público método calculateStockMarketData()
central, de modo que, a fim de criar um objeto StockMarketData
você precisa chamar explicitamente o método. Então, a partir da classe ReportGenerator
eu código:
StockMarketData myData = new StockMarketData(someDate);
myData.calculateStockMarketData();
As primeiras me parece o melhor design, especialmente porque há então nenhuma possibilidade de utilizar as propriedades do objeto antes que eles são inicializados. Mas também estou inseguro sobre as normas relacionadas com a execução de uma grande quantidade de código a partir de um construtor ... Qual eu devo escolher?
Solução
Eu iria com o número 2, especialmente se houver uma possibilidade de adicionar métodos para a classe que não dependem de que os dados de estar lá.
Por outro lado, se você considerar a classe para estar em um estado inválido sem os dados preenchido, você deve fazê-lo na construção.
Outras dicas
Martin Fowler tem escrito um bom ensaio sobre injeção de dependência (Construtor vs. Setter injeção) . Seu conselho é "tanto quanto possível, para criar objetos válidos no tempo de construção".
IMO, é melhor para a construção de objetos válidos se possível, porque torna mais fácil de ler / observar o comportamento do código, desde que você pode assumir que os objetos foram construídos corretamente, e você tem menos bugs relacionados a objetos não sendo preenchido corretamente. A questão do setter vs. construtor injeção é diferente do que você está perguntando sobre porém, que é uma questão de onde para executar a sua lógica de negócios. Eu acho que é melhor usar o construtor para criar um objeto válido e, em seguida, executar a lógica de negócio real em outro método público (o seu nº 2), de modo que a construção do objeto pode acontecer em um horário diferente do que a lógica de negócio real.
Eu sempre carregar explicitamente, pós-construção.
Chamar um banco de dados a partir de um construtor pode fazer para difícil depuração, código mais frágil, inflexível, e causar problemas de desempenho se o uso do objeto de alterações.
Uma boa prática é a de não executar um monte de código dentro de um construtor.