Os benefícios de usar injeção de dependência por construtor

Dherik Barison
CWI Software
Published in
4 min readNov 1, 2018

--

Photo by Sergi Kabrera on Unsplash

Normalmente vemos nos projetos que a forma mais comum de injeção de dependências é a por campo, técnica mais conhecida como Field Injection. Veja um exemplo abaixo deste tipo de injeção usando Java e o framework Spring:

No exemplo acima, estamos injetando o serviço EnderecoService na classe PessoaService.

Basicamente, esta é a forma mais comum de injeção de dependência com Spring e, creio eu, também com outros frameworks.

Esta técnica é, sem dúvida, uma das mais usadas pelos desenvolvedores. Das possíveis explicações para a popularidade dessa forma de injeção de dependência, consigo apontar as seguintes como as mais plausíveis:

  • Simplicidade;
  • Utilização de pouco código;
  • Técnica mais comum ensinada em tutoriais e exemplos pela Internet;
  • Técnica mais adotada em projetos;
  • Desconhecimento de outros métodos de injeção.

E é sobre este último ponto que gostaria de discutir.

Embora seja uma prática muito comum, a injeção de dependência por campo é a que menos traz benefícios ao desenvolvedor e ao código. Eis as razões para isto:

  • Aumenta a dificuldade de mockar dependências: você precisa usar frameworks de reflection para conseguir injetar as dependências no teste unitário;
  • As dependências da classe ficam ocultas: isto cria uma tendência dos desenvolvedores adicionarem mais dependências para a classe sem se preocupar com as consequências, que são: aumento do tamanho da própria classe e aumento da complexidade da mesma;

Quais são as alternativas, então?

Temos duas: a injeção por método (Setter Injection) ou a por construtor (Constructor Injection) da classe. Veja, respectivamente, um exemplo de cada:

A vantagem mais óbvia de ambas, se comparadas com a injeção por campo, é que não é preciso mais apelar para um método de reflection para injetar as dependências na classe em testes. No primeiro caso você pode usar o método set e no segundo o construtor da classe.

Agora, se compararmos a injeção por campo apenas com a injeção por construtor, temos mais algumas vantagens:

  • As dependências da classe ficam expostas: as dependências da classe são mais óbvias se comparadas ao método de injeção por campo ou método, no qual as classes ficam próximas a uma caixa preta. Os desenvolvedores tendem, pela minha experiência, a não se importar com classes com muitas dependências escondidas, que por outro lado ficam bem óbvias quando você tenta mockar elas usando o construtor da classe. A própria “bagunça” que pode ser causada pelo uso do construtor em uma classe com muitas dependências também vira um sinal claro de que há algo errado. Lembre-se: um problema que incomoda os desenvolvedores tem mais sucesso em ser priorizado e resolvido. Lembrando que uma classe com muitas dependências provavelmente deve estar violando o Single Responsibility Principle (SRP).
  • Mock é mais fácil e confiável: comparado ao injeção por campo, é mais fácil mockar as dependências em um teste unitário, porque você não precisa de nenhum contexto de mock ou uso de reflection para acessar a dependência dentro da classe. Também não será enganado por estas técnicas. Você apenas instancia a classe e passa as dependências no construtor: simples e fácil de entender.
  • Ferramentas de análise de código vão te ajudar mais: Ferramentas de análise de código, como o Sonar, podem te avisar sobre uma classe que está ficando muito complexa, porque uma classe com muitos parâmetros no construtor é provavelmente uma classe que precisa de refatoração e, por consequência, as ferramentas de análise de código vão avisar sobre este problema. Estas mesmas ferramentas não conseguem identificar situação similar usando injeção por campo ou método. Aliás, falando em Sonar, ele próprio considera como bug o uso de injeção por campo ao invés do uso por construtor.
  • Código independente: com menos anotações de injeção no seu código, ele fica menos dependente do framework de injeção. Eu sei que a possibilidade de mudar o framework de injeção é bem remota em um projeto, mas muitas vezes é melhor manter o seu código o mais agnóstico possível, algo que aprendi da maneira mais difícil com EJB e usando lookup de serviços.
  • As dependências podem ser imutáveis: a imutabilidade é uma qualidade bem-vinda.
  • Pode prevenir dependência circular: se estiver usando Spring, ele é capaz de detectar dependência circular entre classes usando injeção por construtor.

Para finalizar, a equipe do Spring recomenda também o uso de injeções por construtor:

I think constructor injection is much more usable for application code than it is for framework code. In application code, you inherently have a lesser need for optional values that you need to configure

Pensamentos finais

Se você ainda não está seguro em usar apenas a injeção por construtor, talvez a ideia de usar a injeção por método com a de construtor possa ser útil:

Since you can mix both, Constructor- and Setter-based DI, it is a good rule of thumb to use constructor arguments for mandatory dependencies and setters for optional dependencies

Mas lembre-se que a injeção por campo é, provavelmente, a única opção que deve ser evitada dentre as três.

--

--

Dherik Barison
CWI Software

Java developer, Tech Lead, Stack Overflow enthusiast and contributor: https://dherik.com