Qual é a diferença prática entre os estilos de injeção de dependência?


12

Eu sou novo na injeção de dependência e tenho algumas perguntas sobre qual estilo devo usar em meus aplicativos. Acabei de ler Inversão de controle de contêineres e o padrão de injeção de dependência de Martin Fowler, mas não consigo obter a diferença prática entre construtor, setter e injeção de interface.

Parece-me que os motivos para usar um sobre o outro são apenas uma questão de limpeza e / ou clareza do código. Qual é a diferença? Existem fortes vantagens ou desvantagens em usar um sobre o outro, ou é exatamente o que afirmei antes?

Na minha opinião, a injeção de construtor é a mais intuitiva de todas, assim como a injeção de interface é a menor. Por outro lado, a injeção de setter é um termo intermediário, mas você deve poder alterar a instância do objeto de dependência que você injetou inicialmente? Esse estilo de injeção garante que o objeto que precisa da dependência sempre o injete? Eu acredito que não, mas por favor me corrija se eu estiver errado.


Não tenho certeza do que mais você encontrou ou leu ao longo do caminho. Encontrei alguns tópicos semelhantes aqui e aqui . Eu sou novo mim mesmo, e seria curioso para as respostas que você pode obter :)

@ user1766760 você deveria me ajudar então aqui, minha pergunta está sendo votada para ser encerrada, mais dois votos e pronto !!! Vote na pergunta ou algo assim, não sei o que pode ser feito para evitar o fechamento.
ecampver

erm ... Eu sou novo no SO, então não tenho muita certeza de como posso ajudar / por que está sendo votado para fechar (não vejo nenhuma indicação?). Se eu arriscar um palpite, talvez não seja uma questão de programação específica, mas mais uma discussão?

Você pode expandir um pouco a questão. A injeção de dependência é uma forma de "Inversão de controle". Existem alternativas. Uma alternativa útil, mas pronta para o abuso é o Local do Serviço, por exemplo.
Ian

Respostas:


12

A injeção de construtor tem a vantagem de explicitar a dependência e forçar o cliente a fornecer uma instância. Também pode garantir que o cliente não possa alterar a instância posteriormente. Uma (possível) desvantagem é que você precisa adicionar um parâmetro ao seu construtor.

A Injeção de Setter tem a vantagem de não exigir a adição de um parâmetro ao construtor. Também não requer que o cliente defina a instância. Isso é útil para dependências opcionais. Isso também pode ser útil se você desejar que a classe crie, por exemplo, um repositório de dados real por padrão e, em um teste, você pode usar o configurador para substituí-lo por uma instância de teste.

A injeção de interface , até onde eu sei, não é muito diferente da injeção de incubadora. Nos dois casos, você está (opcionalmente) configurando uma dependência que pode ser alterada posteriormente.

Em última análise, é uma questão de preferência e se é necessária ou não uma dependência . Pessoalmente, uso quase exclusivamente a injeção de construtores. Eu gosto que ele explique as dependências de uma classe, forçando o cliente a fornecer uma instância no construtor. Também gosto que o cliente não possa alterar a instância após o fato.

Muitas vezes, minha única razão para passar em duas implementações separadas é para testar. Na produção, posso passar em a DataRepository, mas nos testes, em FakeDataRepository. Nesse caso, geralmente fornecerei dois construtores: um sem parâmetros e outro que aceita a IDataRepository. Então, no construtor sem parâmetros, encadeará uma chamada para o segundo construtor e passarei a new DataRepository().

Aqui está um exemplo em c #:


public class Foo
{
  private readonly IDataRepository dataRepository;

  public Foo() : this(new DataRepository())
  {
  }

  public Foo(IDataRespository dataRepository)
  {
    this.dataRepository = dataRepository;
  }
}

Isso é conhecido como Injeção de Dependência do Pobre Homem. Gosto porque, no código do cliente de produção, não preciso me repetir tendo várias instruções repetidas que parecem

var foo = new Foo(new DataRepository());
No entanto, ainda posso passar em uma implementação alternativa para teste. Percebo que, com o DI do Poor Man, estou codificando minha dependência, mas isso é aceitável para mim, pois eu o uso principalmente para testes.


obrigado, isso é muito parecido com o que eu entendo, mas ainda assim, existe algum cenário em que você não pode usar injeção de construtor ?
Ecampver

1
Você provavelmente não gostaria de usar injeção de construtor para dependências opcionais. Não consigo pensar em outras razões para não usá-lo.
jhewlett

Eu uso a injeção do configurador de propriedades especificamente para preencher algumas classes de configuração que incluem um grande número de valores. Eu não uso em nenhum outro lugar. Eu sempre sou um pouco duvidoso em defender argumentos opcionais porque há uma boa chance de que isso seja uma infração à regra de responsabilidade única. De regras do curso são feitas para serem quebradas, então ...
Ian

@jhewlett - que é fantástico, eu estive procurando uma técnica stubbing boa simples para teste de unidade que não complicar mais a minha solução - e eu acho que é isso :)
Rocklan

2

As diferenças entre a injeção do construtor e da incubadora já estão descritas adequadamente acima, então não vou detalhar mais sobre elas.

A injeção de interface é uma forma mais avançada de injeção, útil porque permite que a dependência seja decidida no momento em que é usada, e não durante a inicialização do objeto que a usará. Isso permite várias opções úteis:

  • A dependência pode ter um escopo diferente do objeto no qual ele é injetado; por exemplo, você pode usar a injeção de interface para fornecer um objeto para o qual existe por sessão do usuário ou por thread para um singleton global. Sempre que o objeto precisar da dependência, ele chamará o método getter fornecido pela estrutura, e isso poderá retornar resultados diferentes, dependendo da situação em que for chamado.

  • Permite uma inicialização lenta - não é necessário inicializar a dependência até que esteja prestes a ser usada

  • Ele permite que as dependências sejam carregadas de uma cópia em cache quando elas existem ou reinicializadas quando não existem (por exemplo, usando uma SoftReferenceem Java).

Obviamente, técnicas avançadas como essa têm desvantagens; Nesse caso, o principal problema é que o código se torna menos claro (as classes usadas em seu código se tornam abstratas e não há uma implementação concreta óbvia delas, o que pode ser confuso se você não estiver acostumado) e se torna mais dependente na estrutura de injeção de dependência (ainda é possível instanciar seus objetos manualmente, é claro, mas é mais difícil do que com outros estilos de injeção).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.