Primeiro, gostaria de separar a abordagem de design do conceito de frameworks. A injeção de dependência em seu nível mais simples e fundamental é simplesmente:
A parent object provides all the dependencies required to the child object.
É isso. Note que nada disso requer interfaces, frameworks, qualquer estilo de injeção, etc. Para ser justo, aprendi sobre esse padrão há 20 anos. Não é novo.
Devido a mais de 2 pessoas terem confusão sobre o termo pai e filho, no contexto da injeção de dependência:
- O pai é o objeto que instancia e configura o objeto filho que ele usa
- O filho é o componente projetado para ser passivamente instanciado. Ou seja Ele é projetado para usar quaisquer dependências fornecidas pelo pai e não instancia suas próprias dependências.
Injeção de dependência é um padrão para objeto composição .
Por que interfaces?
Interfaces são um contrato. Eles existem para limitar o quão bem acoplados dois objetos podem ser. Nem toda dependência precisa de uma interface, mas ajudam a escrever códigos modulares.
Quando você adiciona o conceito de teste de unidade, você pode ter duas implementações conceituais para qualquer interface: o objeto real que você deseja usar em seu aplicativo e o objeto ridicularizado ou stubbed que você usa para testar o código que depende do objeto. Só isso pode ser justificativa suficiente para a interface.
Por que os frameworks
Inicialmente, a inicialização e o fornecimento de dependências para objetos filho podem ser assustadores quando há um grande número deles. Os frameworks fornecem os seguintes benefícios:
- Dependências de autowiring para componentes
- Configurando os componentes com configurações de algum tipo
- Automatizando o código da placa de caldeira para que você não precise vê-lo escrito em vários locais.
Eles também têm as seguintes desvantagens:
- O objeto pai é um "contêiner" e não há nada em seu código
- Torna os testes mais complicados se você não puder fornecer as dependências diretamente em seu código de teste
- Pode retardar a inicialização, pois resolve todas as dependências usando reflexão e muitos outros truques
- Depuração de tempo de execução pode ser mais difícil, particularmente se o contêiner injetar um proxy entre a interface e o componente real que implementa a interface (programação orientada a aspectos integrada no Spring vem à mente). O contêiner é uma caixa preta e nem sempre é construído com qualquer conceito de facilitar o processo de depuração.
Tudo o que disse, há trade-offs. Para projetos pequenos, onde não há muitas partes móveis, e há poucas razões para usar uma estrutura de DI. No entanto, para projetos mais complicados, onde existem certos componentes já feitos para você, a estrutura pode ser justificada.
E sobre [artigo aleatório na Internet]?
E isso? Muitas vezes as pessoas podem ficar com excesso de zelo e adicionar um monte de restrições e repreendê-lo se você não está fazendo as coisas do "único caminho verdadeiro". Não há um caminho verdadeiro. Veja se você pode extrair algo útil do artigo e ignorar as coisas que você não concorda.
Em suma, pense por si mesmo e tente as coisas.
Trabalhando com "cabeças antigas"
Aprenda o máximo que puder. O que você vai encontrar com muitos desenvolvedores que estão trabalhando em seus 70 anos é que eles aprenderam a não ser dogmáticos sobre muitas coisas. Eles têm métodos com os quais trabalham há décadas que produzem resultados corretos.
Eu tive o privilégio de trabalhar com alguns deles, e eles podem fornecer um feedback brutalmente honesto que faz muito sentido. E onde eles vêem valor, eles adicionam essas ferramentas ao seu repertório.