Sei que este é um debate quente e as opiniões tendem a mudar ao longo do tempo quanto à melhor prática de abordagem.
Eu costumava usar injeção de campo exclusiva para minhas aulas, até começar a ler em diferentes blogs ( ex : petrikainulainen e schauderhaft and fowler ) sobre os benefícios da injeção de construtores. Desde então, mudei minhas metodologias para usar a injeção de construtor para dependências necessárias e a injeção de setter para dependências opcionais.
No entanto, recentemente entrei em um debate com o autor do JMockit - uma estrutura de zombaria - na qual ele vê a injeção de construtores e setters como uma prática ruim e indica que a comunidade JEE concorda com ele.
No mundo de hoje, existe uma maneira preferida de fazer injeção? A injeção de campo é preferida?
Tendo mudado para o injetor de construtor da injeção de campo nos últimos dois anos, acho muito mais claro o uso, mas estou pensando se devo reexaminar meu ponto de vista. O autor de JMockit (Rogério Liesenfeld) é claramente bem versado em DI, então me sinto obrigado a revisar minha abordagem, pois ele se sente tão fortemente contra a injeção de construtor / setter.
fonte
Respostas:
A injeção em campo é um pouco "ação assustadora à distância" para o meu gosto.
Considere o exemplo que você forneceu na sua postagem dos Grupos do Google:
Então, basicamente, o que você está dizendo é que "eu tenho essa classe com estado privado, ao qual anexei
@injectable
anotações, o que significa que o estado pode ser automagicamente preenchido por algum agente de fora, mesmo que meu estado tenha sido declarado privado. "Eu entendo as motivações para isso. É uma tentativa de evitar grande parte da cerimônia que é inerente à criação de uma classe adequadamente. Basicamente, o que se está dizendo é que "estou cansado de escrever todo esse texto padrão, então vou apenas anotar todo o meu estado e deixar o contêiner de DI cuidar de defini-lo para mim".
É um ponto de vista perfeitamente válido. Mas também é uma solução alternativa para os recursos de linguagem que, sem dúvida, não devem ser contornados. Além disso, por que parar por aí? Tradicionalmente, o DI contava com cada classe com uma interface complementar. Por que não eliminar todas essas interfaces com anotações também?
Considere a alternativa (isso será C #, porque eu o conheço melhor, mas provavelmente há um equivalente exato em Java):
Já sei algumas coisas sobre essa aula. É uma classe imutável; O estado pode ser definido apenas no construtor (referências, neste caso em particular). E como tudo deriva de uma interface, eu posso trocar as implementações no construtor, que é onde suas zombarias entram.
Agora, tudo que meu contêiner de DI precisa fazer é refletir sobre o construtor para determinar quais objetos ele precisa atualizar. Mas essa reflexão está sendo feita sobre um membro público, de maneira de primeira classe; isto é, os metadados já fazem parte da classe, tendo sido declarados no construtor, um método cujo objetivo expresso é fornecer à classe as dependências necessárias.
Concedido isso é muito clichê, mas é assim que a linguagem foi projetada. As anotações parecem um truque sujo para algo que deveria ter sido incorporado ao próprio idioma.
fonte
VeracodeService
é quase idêntica à que você escreveu (embora em Java vs C #). NaVeracodeServiceImplTest
verdade, é uma classe de Teste de Unidade. Os@Injectable
campos são essencialmente objetos simulados sendo inseridos no contexto. O@Tested
campo é o objeto / classe com o DI Constructor definido. Concordo com o seu ponto de vista que prefere a injeção do Constructor à injeção de campo. No entanto, como já referi, o autor JMockit sente o oposto e eu estou tentando entender por queO argumento de menos clichê de inicialização de teste é válido, mas há outras preocupações que devem ser levadas em consideração. Primeiro de tudo, você deve responder a uma pergunta:
Quero que minha turma seja instanciada apenas com reflexão?
Usar injeções de campo significa restringir a compatibilidade de uma classe a ambientes de injeção de dependência que instanciam objetos usando reflexão e suportam essas anotações de injeção específicas. Algumas plataformas baseadas na linguagem Java nem suportam reflexão ( GWT ), portanto, a classe injetada em campo não será compatível com elas.
A segunda questão é desempenho . Uma chamada de construtor (direta ou por reflexão) é sempre mais rápida do que várias atribuições de campo de reflexão. As estruturas de injeção de dependência devem usar a análise de reflexão para criar uma árvore de dependência e criar construtores de reflexão. Esse processo causa um impacto adicional no desempenho.
O desempenho afeta a manutenção . Se cada conjunto de testes precisar ser executado em algum tipo de contêiner de injeção de dependência, uma execução de teste de alguns milhares de testes de unidade poderá durar dezenas de minutos. Dependendo do tamanho de uma base de código, isso pode ser um problema.
Isso tudo levanta muitas questões novas:
Geralmente, quanto maior e mais importante é um projeto, mais significativos são esses fatores. Além disso, em termos de qualidade, geralmente gostaríamos de manter o código alto sobre compatibilidade, testabilidade e manutenção. Do ponto de vista filosófico, a injeção de campo quebra o encapsulamento , que é um dos quatro fundamentos da programação orientada a objetos , que é o principal paradigma do Java.
Muitos, muitos argumentos contra a injeção de campo.
fonte
A injeção de campo recebe um voto definitivo de "Não" de mim.
Como Robert Harvey, é um pouco automagico para o meu gosto. Prefiro o código explícito do que o implícito, e tolero a indireção apenas como / quando fornece benefícios claros, pois torna o código mais difícil de entender e raciocinar.
Como Maciej Chałapuk, não gosto de precisar de reflexão ou de uma estrutura de DI / IoC para instanciar uma classe. É como dirigir para Roma para chegar a Paris de Amsterdã.
Lembre-se, eu amo DI e todas as vantagens que isso traz. Só não tenho certeza sobre a necessidade de estruturas para instanciar uma classe. Especialmente o efeito que os contêineres IoC ou outras estruturas DI podem ter no código de teste.
Eu gosto que meus testes sejam muito diretos. Não gosto de passar pelo indireto de configurar contêineres de IoC ou outra estrutura de DI para que eles configurem minha classe em teste. Parece estranho.
E isso torna meus testes dependentes do estado global da estrutura. Ou seja, não posso mais executar dois testes em paralelo que exigem que uma instância da classe X seja configurada com dependências diferentes.
Pelo menos com injeção de construtor e setter, você tem a opção de não usar as estruturas e / ou reflexão em seus testes.
fonte
Bem, isso parece uma discussão polêmica. A primeira coisa que precisa ser abordada é que a injeção de campo é diferente da injeção do setter . Eu já trabalho com algumas pessoas que pensam que a injeção de Field e Setter é a mesma coisa.
Então, para ficar claro:
Injeção em campo:
Injeção de incubadora:
Mas, para mim, eles compartilham as mesmas preocupações. E, meu favorito, a injeção do construtor:
Eu tenho as seguintes razões para acreditar que a injeção do construtor é melhor do que a injeção do setter / field (citarei alguns links do Spring para demonstrar meu argumento):
@AutoWired
propagação entre seu código, seu código depende menos da estrutura. Eu sei que a possibilidade de alterar simplesmente a estrutura de DI em um projeto não justifica isso (quem faz isso, certo?). Mas isso mostra, para mim, um código melhor (eu aprendi isso de maneira difícil com o EJB e as pesquisas). E com o Spring você pode até remover a@AutoWired
anotação usando injeção de construtor.Se você estiver procurando mais informações, recomendo este artigo antigo (mas ainda relevante) do Spring Blog nos dizendo por que eles usam tanta injeção de setter e a recomendação para usar a injeção de construtor:
E esta nota sobre por que eles acreditam que o construtor é mais adequado para o código do aplicativo:
Pensamentos finais
Se você não tem certeza da vantagem do construtor, talvez a idéia de misturar o setter (não o campo) com a injeção do construtor seja uma opção, conforme explicado pela equipe do Spring :
Mas lembre-se de que a injeção de campo é provavelmente a que deve ser evitada entre as três.
fonte
É provável que sua dependência mude durante a vida útil da classe? Nesse caso, use injeção de campo / propriedade. Caso contrário, use injeção de construtor.
fonte