design patterns - vantagens - O que é injeção de dependência?




vantagens injeção de dependencia (20)

Várias perguntas já foram postadas com perguntas específicas sobre injeção de dependência , como quando usá-la e quais estruturas estão lá para ela. Contudo,

O que é injeção de dependência e quando / por que deve ou não deve ser usado?


O que é injeção de dependência?

Injeção de Dependência (DI) significa dissociar os objetos que dependem um do outro. Digamos que o objeto A depende do Objeto B, então a ideia é dissociar esses objetos um do outro. Nós não precisamos codificar o objeto usando uma nova palavra-chave, em vez de compartilhar dependências para objetos em tempo de execução, apesar do tempo de compilação. Se falamos sobre

Como a Injeção de Dependência funciona na Primavera:

Não precisamos codificar o objeto usando a nova palavra-chave, mas definir a dependência do bean no arquivo de configuração. O contêiner de mola será responsável por enganchar tudo.

Inversão de Controle (IOC)

O COI é um conceito geral e pode ser expresso de muitas maneiras diferentes e a Injeção de Dependência é um exemplo concreto do COI.

Dois tipos de injeção de dependência:

  1. Injeção de Construtor
  2. Injeção Setter

1. Injeção de dependência baseada em construtor:

A DI baseada em construtor é realizada quando o contêiner chama um construtor de classe com um número de argumentos, cada um representando uma dependência em outra classe.

public class Triangle {

private String type;

public String getType(){
    return type;
 }

public Triangle(String type){   //constructor injection
    this.type=type;
 }
}
<bean id=triangle" class ="com.test.dependencyInjection.Triangle">
        <constructor-arg value="20"/>
  </bean>

2. Injeção de dependência baseada em setter:

A DI baseada em setter é realizada pelos métodos setter de chamada de contêiner em seus beans após chamar um construtor sem argumento ou um método factory estático sem argumento para instanciar seu bean.

public class Triangle{

 private String type;

 public String getType(){
    return type;
  }
 public void setType(String type){          //setter injection
    this.type = type;
  }
 }

<!-- setter injection -->
 <bean id="triangle" class="com.test.dependencyInjection.Triangle">
        <property name="type" value="equivialteral"/>

NOTA: É uma boa regra geral usar argumentos de construtor para dependências obrigatórias e setters para dependências opcionais. Observe que o uso da anotação com base na anotação @Required em um setter pode ser usado para fazer os setters como dependências necessárias.


A melhor definição que encontrei até agora é a de James Shore :

"Injeção de Dependência" é um termo de 25 dólares para um conceito de 5 centavos. [...] Injeção de dependência significa dar a um objeto suas variáveis ​​de instância. [...].

um artigo de Martin Fowler que pode ser útil também.

Injeção de dependência é basicamente fornecer os objetos que um objeto precisa (suas dependências) em vez de fazê-lo construí-los. É uma técnica muito útil para testes, pois permite que as dependências sejam ridicularizadas ou apagadas.

Dependências podem ser injetadas em objetos por vários meios (como injeção de construtor ou injeção de setter). Pode-se até usar estruturas especializadas de injeção de dependência (por exemplo, Spring) para fazer isso, mas elas certamente não são necessárias. Você não precisa que essas estruturas tenham injeção de dependência. Instanciar e passar objetos (dependências) explicitamente é uma injeção tão boa quanto a injeção pelo framework.


Basicamente, em vez de ter seus objetos criando uma dependência ou pedindo a um objeto de fábrica para fazer um para eles, você passa as dependências necessárias para o objeto externamente e torna o problema de outra pessoa. Esse "alguém" é um objeto mais adiante no gráfico de dependência ou um injetor de dependência (framework) que constrói o gráfico de dependência. Uma dependência como eu estou usando aqui é qualquer outro objeto que o objeto atual precisa manter uma referência.

Uma das principais vantagens da injeção de dependência é que ela pode tornar os lotes de teste mais fáceis. Suponha que você tenha um objeto que em seu construtor faça algo como:

public SomeClass() {
    myObject = Factory.getObject();
}

Isso pode ser problemático quando tudo que você quer fazer é executar alguns testes de unidade em SomeClass, especialmente se myObject é algo que faz disco complexo ou acesso à rede. Então agora você está olhando para mocking myObject mas também de alguma forma interceptar a chamada de fábrica. Difícil. Em vez disso, passe o objeto como um argumento para o construtor. Agora você mudou o problema para outro lugar, mas o teste pode se tornar muito mais fácil. Basta fazer um myObject fictício e passar isso para dentro. O construtor agora seria parecido com:

public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

Este é um estilo de injeção de dependência - através do construtor. Vários mecanismos são possíveis.

  • Conforme observado nos comentários, uma alternativa comum é definir um construtor do-nothing e ter as dependências injetadas por meio de setters de propriedades (h / t @MikeVella).
  • Martin Fowler documenta uma terceira alternativa (h / t @MarcDix), onde as classes explicitamente implementam uma interface para as dependências que desejam injetadas.

Quando não estiver usando injeção de dependência (como em classes que fazem muito trabalho em seus construtores, etc.), tende a se tornar muito mais difícil isolar componentes no teste de unidade.

Em 2013, quando escrevi essa resposta, esse era um tema importante no Blog de testes do Google . Isso continua a ser a maior vantagem para mim, pois você pode nem sempre precisar da flexibilidade extra em seu design de tempo de execução (por exemplo, para localizador de serviço ou padrões semelhantes), mas geralmente é necessário isolar suas classes durante os testes.


Injeção de dependência é uma prática em que os objetos são projetados de uma maneira em que eles recebem instâncias dos objetos de outras partes do código, em vez de construí-los internamente. Isto significa que qualquer objeto implementando a interface que é requerida pelo objeto pode ser substituído sem alterar o código, o que simplifica o teste e melhora o desacoplamento.

Por exemplo, considere estas clases:

public class PersonService {
  public void addManager( Person employee, Person newManager ) { ... }
  public void removeManager( Person employee, Person oldManager ) { ... }
  public Group getGroupByManager( Person manager ) { ... }
}

public class GroupMembershipService() {
  public void addPersonToGroup( Person person, Group group ) { ... }
  public void removePersonFromGroup( Person person, Group group ) { ... }
} 

Neste exemplo, a implementação de PersonService::addManager e PersonService::removeManager precisaria de uma instância do GroupMembershipService para fazer seu trabalho. Sem Dependency Injection, a maneira tradicional de fazer isso seria instanciar um novo GroupMembershipService no construtor do PersonService e usar esse atributo de instância em ambas as funções. No entanto, se o construtor do GroupMembershipService tiver vários requisitos, ou, pior ainda, houver alguns "setters" de inicialização que precisam ser chamados no GroupMembershipService , o código cresce rapidamente, e o PersonService agora depende não apenas do GroupMembershipService mas também tudo o mais que o GroupMembershipService depende. Além disso, a vinculação ao GroupMembershipService é codificada PersonService no PersonService que significa que você não pode " GroupMembershipService " um GroupMembershipService para fins de teste ou usar um padrão de estratégia em diferentes partes de seu aplicativo.

Com a Injeção de Dependência, em vez de instanciar o GroupMembershipService no seu PersonService , você pode passá-lo para o construtor PersonService ou então adicionar uma Property (getter e setter) para definir uma instância local dele. Isso significa que o seu PersonService não precisa mais se preocupar com como criar um GroupMembershipService , ele apenas aceita os que são fornecidos e trabalha com eles. Isso também significa que qualquer coisa que seja uma subclasse de GroupMembershipService ou implemente a interface GroupMembershipService pode ser "injetada" no PersonService , e o PersonService não precisa saber sobre a alteração.


Vamos imaginar que você queira ir pescar:

  • Sem injeção de dependência, você precisa cuidar de tudo sozinho. Você precisa encontrar um barco, comprar uma vara de pescar, procurar por iscas, etc. É possível, é claro, mas isso coloca muita responsabilidade em você. Em termos de software, isso significa que você precisa fazer uma pesquisa para todas essas coisas.

  • Com a injeção de dependência, outra pessoa cuida de toda a preparação e disponibiliza o equipamento necessário para você. Você receberá ("injetado") o barco, a vara de pescar e a isca - tudo pronto para uso.


Vamos tentar um exemplo simples com as classes Car e Engine , qualquer carro precisa de um motor para ir a qualquer lugar, pelo menos por enquanto. Então, abaixo, como o código ficará sem injeção de dependência.

public class Car
{
    public Car()
    {
        GasEngine engine = new GasEngine();
        engine.Start();
    }
}

public class GasEngine
{
    public void Start()
    {
        Console.WriteLine("I use gas as my fuel!");
    }
}

E para instanciar a classe Car, usaremos o próximo código:

Car car = new Car();

O problema com este código que nós acoplamos fortemente ao GasEngine e se nós decidirmos mudá-lo para o ElectricityEngine, então nós precisaremos reescrever a classe Car. E quanto maior o aplicativo, mais problemas e dor de cabeça, teremos que adicionar e usar um novo tipo de mecanismo.

Em outras palavras, com essa abordagem, nossa classe Car de alto nível depende da classe GasEngine de nível inferior, que viola o Princípio de Inversão de Dependência (DIP) do SOLID. O DIP sugere que devemos depender de abstrações, não de classes concretas. Então, para satisfazer isso, introduzimos a interface IEngine e reescrevemos o código como abaixo:

    public interface IEngine
    {
        void Start();
    }

    public class GasEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I use gas as my fuel!");
        }
    }

    public class ElectricityEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I am electrocar");
        }
    }

    public class Car
    {
        private readonly IEngine _engine;
        public Car(IEngine engine)
        {
            _engine = engine;
        }

        public void Run()
        {
            _engine.Start();
        }
    }

Agora nossa classe Car depende apenas da interface IEngine, não de uma implementação específica do mecanismo. Agora, o único truque é como criamos uma instância do carro e damos a ela uma classe concreta de Engine, como GasEngine ou ElectricityEngine. É aí que entra a injeção de dependência .

   Car gasCar = new Car(new GasEngine());
   gasCar.Run();
   Car electroCar = new Car(new ElectricityEngine());
   electroCar.Run();

Aqui, basicamente, injetamos (passamos) nossa dependência (instância do mecanismo) para o construtor Car. Então, agora nossas classes têm um baixo acoplamento entre objetos e suas dependências, e podemos facilmente adicionar novos tipos de motores sem alterar a classe Car.

O principal benefício da Injeção de Dependência é que as classes são mais fracamente acopladas, porque elas não têm dependências codificadas. Isto segue o Princípio de Inversão de Dependência, que foi mencionado acima. Em vez de referenciar implementações específicas, as classes solicitam abstrações (geralmente interfaces ) que são fornecidas a elas quando a classe é construída.

Assim, no final, a injeção de dependência é apenas uma técnica para obter um acoplamento flexível entre objetos e suas dependências. Em vez de instanciar diretamente as dependências de que a classe precisa para executar suas ações, as dependências são fornecidas à classe (com mais freqüência) por meio da injeção de construtor.

Além disso, quando temos muitas dependências, é uma boa prática usar contêineres de Inversão de Controle (IoC), que podemos identificar quais interfaces devem ser mapeadas para quais implementações concretas para todas as nossas dependências e podemos resolvê-las quando construir nosso objeto. Por exemplo, podemos especificar no mapeamento para o contêiner IoC que a dependência IEngine deve ser mapeada para a classe GasEngine e quando solicitarmos ao contêiner IoC uma instância de nossa classe Car , ela construirá automaticamente nossa classe Car com uma dependência GasEngine Transmitido.

UPDATE: Assistiu ao curso sobre EF Core de Julie Lerman recentemente e também gostou de sua curta definição sobre DI.

Injeção de dependência é um padrão para permitir que seu aplicativo injete objetos em tempo real para as classes que precisam deles, sem forçar essas classes a serem responsáveis ​​por esses objetos. Ele permite que seu código seja mais solto, e o Entity Framework Core conecta-se a esse mesmo sistema de serviços.


Injeção de Dependência significa uma maneira (na verdade, de qualquer forma ) de uma parte do código (por exemplo, uma classe) ter acesso a dependências (outras partes do código, por exemplo, outras classes, depende) de forma modular sem que elas sejam codificadas (então eles podem mudar ou ser anulados livremente, ou até mesmo serem carregados em outro momento, conforme necessário)

(e ps, sim, tornou-se um nome excessivamente sensacionalista para um conceito bastante simples) , meus .25centavos


Eu encontrei este exemplo engraçado em termos de acoplamento solto :

Qualquer aplicativo é composto de muitos objetos que colaboram entre si para executar algumas coisas úteis. Tradicionalmente, cada objeto é responsável por obter suas próprias referências aos objetos dependentes (dependências) com os quais colabora. Isso leva a classes altamente acopladas e a códigos difíceis de testar.

Por exemplo, considere um objeto Car .

Um Car depende de rodas, motor, combustível, bateria, etc. Tradicionalmente, definimos a marca desses objetos dependentes juntamente com a definição do objeto Car .

Sem injeção de dependência (DI):

class Car{
  private Wheel wh = new NepaliRubberWheel();
  private Battery bt = new ExcideBattery();

  //The rest
}

Aqui, o objeto Car é responsável por criar os objetos dependentes.

E se quisermos mudar o tipo de seu objeto dependente - digamos Wheel - depois que o NepaliRubberWheel() inicial NepaliRubberWheel() perfurar? Precisamos recriar o objeto Car com sua nova dependência, como ChineseRubberWheel() , mas somente o fabricante Car pode fazer isso.

Então, o que a Dependency Injection nos faz por ...?

Ao usar a injeção de dependência, os objetos recebem suas dependências no tempo de execução, em vez do tempo de compilação (tempo de fabricação do carro) . Para que possamos agora mudar a Wheel sempre que quisermos. Aqui, a dependency ( wheel ) pode ser injetada no Car em tempo de execução.

Depois de usar a injeção de dependência:

Aqui, estamos injetando as dependências (roda e bateria) em tempo de execução. Daí o termo: Injeção de Dependência.

class Car{
  private Wheel wh = [Inject an Instance of Wheel (dependency of car) at runtime]
  private Battery bt = [Inject an Instance of Battery (dependency of car) at runtime]
  Car(Wheel wh,Battery bt) {
      this.wh = wh;
      this.bt = bt;
  }
  //Or we can have setters
  void setWheel(Wheel wh) {
      this.wh = wh;
  }
}

Fonte: Entendendo a injeção de dependência


O que é injeção de dependência (DI)?

Como outros disseram, a Injeção de Dependência (DI) remove a responsabilidade da criação direta e do gerenciamento do tempo de vida de outras instâncias de objeto sobre as quais nossa classe de interesse (classe de consumidor) é dependente (no sentido da UML ). Em vez disso, essas instâncias são passadas para nossa classe consumer, normalmente como parâmetros de construtor ou por meio de setters de propriedade (o gerenciamento do objeto de dependência que instancia e passa para a classe de consumidor é normalmente executado por um contêiner de Inversion of Control (IoC) , mas isso é outro tópico) .

DI, DIP e SOLID

Especificamente, no paradigma dos princípios SOLID do Projeto Orientado a Objetos , de Robert C Martin, a DI é uma das possíveis implementações do Princípio da Inversão de Dependência (DIP) . O DIP é o D do mantra SOLID - outras implementações DIP incluem o Service Locator e padrões de Plugin.

O objetivo do DIP é dissociar as dependências apertadas e concretas entre as classes e, em vez disso, soltar o acoplamento por meio de uma abstração, que pode ser obtida através de uma interface , abstract class ou pure virtual class , dependendo da linguagem e abordagem utilizada. .

Sem o DIP, nosso código (eu chamei isso de 'classe consumidora') está diretamente acoplado a uma dependência concreta e também é frequentemente sobrecarregado com a responsabilidade de saber como obter e gerenciar uma instância dessa dependência, ou seja, conceitualmente:

"I need to create/use a Foo and invoke method `GetBar()`"

Considerando que, após a aplicação do DIP, o requisito é afrouxado, e a preocupação de obter e gerenciar a vida útil da dependência de Foo foi removida:

"I need to invoke something which offers `GetBar()`"

Por que usar DIP (e DI)?

Desacoplar dependências entre classes dessa forma permite a fácil substituição dessas classes de dependência por outras implementações que também preencham os pré-requisitos da abstração (por exemplo, a dependência pode ser alternada com outra implementação da mesma interface). Além disso, como outros já mencionaram, possivelmente o motivo mais comum para dissociar classes via DIP é permitir que uma classe consumidora seja testada isoladamente, já que essas mesmas dependências podem agora ser apagadas e / ou ridicularizadas.

Uma conseqüência da DI é que o gerenciamento de vida útil das instâncias de objetos de dependência não é mais controlado por uma classe consumidora, pois o objeto de dependência agora é passado para a classe consumidora (via injeção de construtor ou setter).

Isso pode ser visto de diferentes maneiras:

  • Se o controle de tempo de vida das dependências pela classe consumidora precisar ser retido, o controle poderá ser restabelecido com a injeção de uma fábrica (abstrata) para criar as instâncias da classe de dependência na classe do consumidor. O consumidor poderá obter instâncias por meio de um Create na fábrica, conforme necessário, e descartar essas instâncias depois de concluídas.
  • Ou, o controle de tempo de vida das instâncias de dependência pode ser liberado para um contêiner IoC (mais sobre isso abaixo).

Quando usar DI?

  • Onde provavelmente haverá a necessidade de substituir uma dependência por uma implementação equivalente,
  • Sempre que precisar testar os métodos de uma classe isoladamente de suas dependências,
  • Onde a incerteza do tempo de vida de uma dependência pode justificar a experimentação (por exemplo, Hey, MyDepClass é thread-safe - e se nós torná-lo um singleton e injetar a mesma instância em todos os consumidores?)

Exemplo

Aqui está uma implementação simples de c #. Dada a classe Consuming abaixo:

public class MyLogger
{
   public void LogRecord(string somethingToLog)
   {
      Console.WriteLine("{0:HH:mm:ss} - {1}", DateTime.Now, somethingToLog);
   }
}

Embora aparentemente inócuo, ele tem duas dependências static em duas outras classes, System.DateTime e System.Console , que não apenas limitam as opções de saída de logging (o log no console será inútil se ninguém estiver assistindo), mas pior, é difícil para testar automaticamente, dada a dependência de um relógio do sistema não-determinístico.

Podemos, no entanto, aplicar o DIP a essa classe, abstraindo a preocupação do registro de data e hora como uma dependência e acoplando o MyLogger apenas a uma interface simples:

public interface IClock
{
    DateTime Now { get; }
}

Também podemos soltar a dependência do Console para uma abstração, como um TextWriter . A Injeção de Dependência é tipicamente implementada como injeção de constructor (passando uma abstração para uma dependência como um parâmetro para o construtor de uma classe consumidora) ou Setter Injection (passando a dependência através de um setXyz() setter ou uma Propriedade .Net com {set;} definiram). A Injeção de Construtor é preferencial, pois isso garante que a classe estará em um estado correto após a construção e permitirá que os campos de dependência internos sejam marcados como readonly (C #) ou final (Java). Então, usando injeção de construtor no exemplo acima, isso nos deixa com:

public class MyLogger : ILogger // Others will depend on our logger.
{
    private readonly TextWriter _output;
    private readonly IClock _clock;

    // Dependencies are injected through the constructor
    public MyLogger(TextWriter stream, IClock clock)
    {
        _output = stream;
        _clock = clock;
    }

    public void LogRecord(string somethingToLog)
    {
        // We can now use our dependencies through the abstraction 
        // and without knowledge of the lifespans of the dependencies
        _output.Write("{0:yyyy-MM-dd HH:mm:ss} - {1}", _clock.Now, somethingToLog);
    }
}

(Um Clock concreto precisa ser fornecido, o que naturalmente poderia reverter para DateTime.Now , e as duas dependências precisam ser fornecidas por um contêiner IoC via injeção de construtor)

Um Teste de Unidade automatizado pode ser construído, o que prova definitivamente que nosso registrador está funcionando corretamente, já que agora temos controle sobre as dependências - o tempo, e podemos espionar a saída escrita:

[Test]
public void LoggingMustRecordAllInformationAndStampTheTime()
{
    // Arrange
    var mockClock = new Mock<IClock>();
    mockClock.Setup(c => c.Now).Returns(new DateTime(2015, 4, 11, 12, 31, 45));
    var fakeConsole = new StringWriter();

    // Act
    new MyLogger(fakeConsole, mockClock.Object)
        .LogRecord("Foo");

    // Assert
    Assert.AreEqual("2015-04-11 12:31:45 - Foo", fakeConsole.ToString());
}

Próximos passos

A injeção de dependência é invariavelmente associada a um contêiner Inversion of Control (IoC) , para injetar (fornecer) as instâncias de dependência concretas e para gerenciar instâncias de vida útil. Durante o processo de configuração / bootstrapping, os contêineres IoC permitem que os seguintes IoC sejam definidos:

  • mapeamento entre cada abstração e a implementação concreta configurada (por exemplo, "sempre que um consumidor solicitar um IBar , retornar uma instância do ConcreteBar " )
  • as políticas podem ser configuradas para o gerenciamento de duração de cada dependência, por exemplo, para criar um novo objeto para cada instância do consumidor, para compartilhar uma instância de dependência singleton em todos os consumidores, para compartilhar a mesma instância de dependência somente no mesmo thread, etc.
  • Em .Net, os contêineres IoC reconhecem protocolos como IDisposable e assumem a responsabilidade de Disposing dependências de acordo com o gerenciamento de tempo de vida configurado.

Normalmente, uma vez que os contêineres IoC tenham sido configurados / bootstrap, eles operam perfeitamente em segundo plano, permitindo que o codificador se concentre no código em questão, em vez de se preocupar com dependências.

A chave para o código amigável ao DI é evitar o acoplamento estático de classes e não usar o new () para a criação de Dependências.

Como no exemplo acima, o desacoplamento de dependências requer algum esforço de projeto, e para o desenvolvedor, há uma mudança de paradigma necessária para quebrar o hábito de newdepender diretamente de dependências e, em vez disso, confiar no contêiner para gerenciar dependências.

Mas os benefícios são muitos, especialmente na capacidade de testar exaustivamente sua classe de interesse.

Nota : A criação / mapeamento / projeção (via new ..()) de projeções PTO / POJO / Serialização DTOs / Gráficos de Entidades / Anônimas JSON et al - isto é, classes ou registros "Somente dados" - usados ​​ou retornados de métodos não são considerados Dependências (no UML) e não sujeito a DI. Usando newpara projetar estes está bem.


Todas as respostas acima são boas, meu objetivo é explicar o conceito de forma simples para que qualquer pessoa sem conhecimento de programação também possa entender o conceito

A injeção de dependência é um dos padrões de projeto que nos ajuda a criar sistemas complexos de maneira mais simples.

Podemos ver uma ampla variedade de aplicações desse padrão no nosso dia a dia. Alguns dos exemplos são gravador de fita, VCD, CD Drive etc.

A imagem acima é uma imagem de gravador portátil Reel-to-reel, meados do século XX. Source .

A principal intenção de uma máquina gravadora é gravar ou reproduzir sons.

Ao projetar um sistema, é necessário um rolo para gravar ou reproduzir som ou música. Existem duas possibilidades para projetar este sistema

  1. podemos colocar o carretel dentro da máquina
  2. podemos fornecer um gancho para o carretel onde ele pode ser colocado.

Se usarmos o primeiro, precisamos abrir a máquina para trocar o rolo. Se optarmos pelo segundo, que é colocar um gancho para o carretel, estamos obtendo um benefício adicional de tocar qualquer música trocando o rolo. e também reduzindo a função apenas para tocar o que estiver no rolo.

Assim como a sábia injeção de dependência é o processo de externalização das dependências para focar apenas na funcionalidade específica do componente, de forma que os componentes independentes possam ser acoplados para formar um sistema complexo.

Os principais benefícios que alcançamos usando injeção de dependência.

  • Alta coesão e baixo acoplamento.
  • Dependência externalizante e olhando apenas para a responsabilidade.
  • Fazendo coisas como componentes e combinando para formar um grande sistema com alta capacidade.
  • Ela ajuda a desenvolver componentes de alta qualidade, já que eles são desenvolvidos de forma independente e são devidamente testados.
  • Isso ajuda a substituir o componente por outro, se um falhar.

Hoje em dia, esses conceitos formam a base de estruturas bem conhecidas no mundo da programação. O Spring Angular etc são os frameworks de software bem conhecidos construídos no topo deste conceito

Injeção de dependência é um padrão usado para criar instâncias de objetos nos quais outros objetos dependem sem saber em tempo de compilação qual classe será usada para fornecer essa funcionalidade ou simplesmente a maneira de injetar propriedades em um objeto é chamada de injeção de dependência.

Exemplo para injeção de dependência

Anteriormente estamos escrevendo código como este

Public MyClass{
 DependentClass dependentObject
 /*
  At somewhere in our code we need to instantiate 
  the object with new operator  inorder to use it or perform some method.
  */ 
  dependentObject= new DependentClass();
  dependentObject.someMethod();
}

Com injeção de dependência, o injetor de dependência vai tirar a instanciação para nós

Public MyClass{
 /* Dependency injector will instantiate object*/
 DependentClass dependentObject

 /*
  At somewhere in our code we perform some method. 
  The process of  instantiation will be handled by the dependency injector
 */ 

  dependentObject.someMethod();
}

Você também pode ler

Diferença entre Inversão de Controle e Injeção de Dependência


Injeção de dependência é o coração do conceito relacionado com o Spring Framework. Enquanto a criação da estrutura de qualquer mola de projeto pode desempenhar um papel vital, e aqui a injeção de dependência vem no jarro.

Na verdade, suponha que em java você tenha criado duas classes diferentes como classe A e classe B, e qualquer que seja a função disponível na classe B que você deseja usar na classe A, então a injeção de dependência pode ser usada. onde você pode criar objetos de uma classe em outra, da mesma forma que você pode injetar uma classe inteira em outra classe para torná-la acessível. assim a dependência pode ser superada.

INJEÇÃO DE DEPENDÊNCIA É COLAR SIMPLESMENTE DUAS CLASSES E AO MESMO TEMPO MANTER-SE SEPARADO.


A Injeção de Dependência (DI) faz parte da prática do Princípio de Inversão de Dependência (DIP), que também é chamada de Inversão de Controle (IoC). Basicamente, você precisa fazer o DIP porque deseja tornar seu código mais modular e testável por unidade, em vez de apenas um sistema monolítico. Então você começa a identificar partes do código que podem ser separadas da classe e abstraídas. Agora a implementação da abstração precisa ser injetada de fora da classe. Normalmente isto pode ser feito via construtor. Então você cria um construtor que aceita a abstração como um parâmetro, e isso é chamado de injeção de dependência (via construtor). Para mais explicações sobre o recipiente DIP, DI e IoC, você pode ler Here


As respostas populares são inúteis, porque definem a injeção de dependência de uma maneira que não é útil. Vamos concordar que por "dependência" queremos dizer algum outro objeto pré-existente que nosso objeto X precisa. Mas nós não dizemos que estamos fazendo "injeção de dependência" quando dizemos

Client client = new Client();
client.setService(new Service());
client.doSomeThingInClient();

Apenas chamamos esses parâmetros de passagem para o construtor. Temos feito isso regularmente desde que os construtores foram inventados.

"Injeção de dependência" é considerado um tipo de "inversão de controle", o que significa que alguma lógica é retirada do chamador. Esse não é o caso quando o chamador passa parâmetros, então se isso fosse DI, DI não implicaria inversão de controle.

DI significa que existe um nível intermediário entre o chamador e o construtor que gerencia as dependências. Um Makefile é um exemplo simples de injeção de dependência. O "chamador" é a pessoa digitando "make bar" na linha de comando, e o "construtor" é o compilador. O Makefile especifica que a barra depende de foo e faz uma

public class Injector {
    public static Service provideService(){
        return new Service();
    }

    public static IDatabase provideDatatBase(){
        return new SqliteDatabase();
    }
    public static ObjectA provideObjectA(){
        return new ObjectA(provideService(...));
    }
}

antes de fazer um

Service service = Injector.provideService();

A pessoa que digitar "make bar" não precisa saber que a barra depende do foo. A dependência foi injetada entre "make bar" e gcc.

O objetivo principal do nível intermediário não é apenas passar as dependências para o construtor, mas listar todas as dependências em apenas um lugar e ocultá-las do codificador (não fazer com que o codificador as forneça).

Normalmente, o nível intermediário fornece fábricas para os objetos construídos, que devem fornecer um papel que cada tipo de objeto solicitado deve satisfazer. Isso porque, por ter um nível intermediário que oculta os detalhes da construção, você já incorreu na penalidade de abstração imposta pelas fábricas, portanto é melhor usar fábricas.



Eu sei que já existem muitas respostas, mas achei isso muito útil: http://tutorials.jenkov.com/dependency-injection/index.html

Nenhuma Dependência:

Client client = new Client(new Service());
// Client client = new Client(new Service(), new SqliteDatabase());
client.doSomeThingInClient();

Dependência:

public class Client {
    Service service;

    public void setService(Service service) {
        this.service = service;
    }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Observe como a DataSourceImplinstanciação é movida para um construtor. O construtor usa quatro parâmetros que são os quatro valores necessários pelo DataSourceImpl. Embora a MyDaoclasse ainda dependa desses quatro valores, ela não satisfaz mais essas dependências. Eles são fornecidos por qualquer classe que crie uma MyDaoinstância.


Exemplo, temos 2 classes Cliente Service. ClientusaráService

public class MyDao {

  protected DataSource dataSource =
    new DataSourceImpl("driver", "url", "user", "password");

  //data access methods...
  public Person readPerson(int primaryKey) {...}

}

Sem injeção de dependência

Caminho 1)

public class MyDao {

  protected DataSource dataSource = null;

  public MyDao(String driver, String url, String user, String
 password){
    this.dataSource = new DataSourceImpl(driver, url, user, password);
  }

  //data access methods...
  public Person readPerson(int primaryKey)
  {...}

}

Caminho 2)

$foo = Foo->new($bar);

Caminho 3)

gcc -c foo.cpp; gcc -c bar.cpp

1) 2) 3) usando

gcc foo.o bar.o -o bar

Vantagens

  • Simples

Desvantagens

  • Difícil para a Clientaula de teste
  • Quando mudamos de Serviceconstrutor, precisamos mudar o código em todo lugar criar Serviceobjeto

Use Injeção de Dependência

Maneira 1) Injeção de construtor

public class Service {
    public void doSomeThingInService() {
        // ...
    }
}

Usando

public class Client {
    public void doSomeThingInClient() {
        Service service = new Service();
        service.doSomeThingInService();
    }
}

Maneira 2) Injeção Setter

public class Client {
    Service service = new Service();
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Usando

public class Client {
    Service service;
    public Client() {
        service = new Service();
    }
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Maneira 3) Injeção de interface

Verifique https://en.wikipedia.org/wiki/Dependency_injection

===

Agora, esse código já é seguido Dependency Injectione é mais fácil para a Clientclasse de teste .
No entanto, ainda usamos new Service()muito tempo e não é bom quando o Serviceconstrutor de mudanças . Para evitar isso, podemos usar o injetor de DI como
1) manual simplesInjector

Client client = new Client();
client.doSomeThingInService();

Usando

public class Client {
    Service service;

    Client(Service service) {
        this.service = service;
    }

    // Example Client has 2 dependency 
    // Client(Service service, IDatabas database) {
    //    this.service = service;
    //    this.database = database;
    // }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

2) Use biblioteca: Para Android dagger2

Vantagens

  • Faça o teste mais fácil
  • Quando você muda o Service, você só precisa alterá-lo na classe Injector
  • Se você usar use Constructor Injection, quando você olhar para construtor Client, você verá quantas dependências de Clientclasse

Desvantagens

  • Se você usa use Constructor Injection, o Serviceobjeto é criado quando Clientcriado, em algum momento nós usamos a função na Clientclasse sem uso, Serviceentão o criado Serviceé desperdiçado

Definição de Injeção de Dependência

https://en.wikipedia.org/wiki/Dependency_injection

Uma dependência é um objeto que pode ser usado ( Service)
Uma injeção é a passagem de uma dependência ( Service) para um objeto dependente ( Client) que a usaria


Injeção de dependência é uma solução possível para o que poderia ser chamado de "Obfusão de Dependência". Dependência A ofuscação é um método de tirar a natureza 'óbvia' do processo de fornecer uma dependência a uma classe que a requer e, portanto, ofuscar, de alguma forma, a provisão da dita dependência à dita classe. Isto não é necessariamente uma coisa ruim. De fato, ofuscando a maneira pela qual uma dependência é fornecida a uma classe, algo fora da classe é responsável por criar a dependência, o que significa que, em vários cenários, uma implementação diferente da dependência pode ser fornecida à classe sem fazer nenhuma alteração. para a aula. Isso é ótimo para alternar entre os modos de produção e teste (por exemplo, usando uma dependência de serviço 'simulada').

Infelizmente a parte ruim é que algumas pessoas assumiram que você precisa de um framework especializado para fazer ofuscação de dependência e que você é de alguma forma um programador 'menor' se você optar por não usar uma estrutura específica para fazê-lo. Outro mito extremamente perturbador, acreditado por muitos, é que a injeção de dependência é a única maneira de alcançar a ofuscação da dependência. Isso é demonstrável e historicamente e, obviamente, 100% errado, mas você terá dificuldade em convencer algumas pessoas de que existem alternativas à injeção de dependência para seus requisitos de ofuscação de dependência.

Os programadores entenderam o requisito de ofuscação de dependência durante anos e muitas soluções alternativas evoluíram antes e depois que a injeção de dependência foi concebida. Há padrões de Fábrica, mas também há muitas opções usando ThreadLocal, onde não é necessária injeção em uma instância específica - a dependência é efetivamente injetada no encadeamento, o que tem a vantagem de disponibilizar o objeto (por métodos getter de conveniência) para qualquerclasse que o requer sem ter que adicionar anotações às classes que o exigem e configurar uma "cola" intrincada de XML para que isso aconteça. Quando suas dependências são necessárias para persistência (JPA / JDO ou qualquer outra coisa), ela permite alcançar a 'persistência de traninstalação' muito mais fácil e com classes de modelo de domínio e modelo de negócio compostas apenas de POJOs (ou seja, sem quadro específico / bloqueado em anotações).


Injeção de dependência (DI) é um dos padrões de design, que usa o recurso básico de OOP - o relacionamento em um objeto com outro objeto. Enquanto herança herda um objeto para fazer mais complexo e específico, outro objeto, relacionamento ou associação simplesmente cria um ponteiro para outro objeto de um objeto usando o atributo. O poder do DI é em combinação com outros recursos do OOP, assim como interfaces e código de ocultação. Suponha que tenhamos um cliente (assinante) na biblioteca, que pode emprestar apenas um livro para simplificar.

Interface do livro:

package com.deepam.hidden;

public interface BookInterface {

public BookInterface setHeight(int height);
public BookInterface setPages(int pages);   
public int getHeight();
public int getPages();  

public String toString();
}

Em seguida, podemos ter muitos tipos de livros; um do tipo é ficção:

package com.deepam.hidden;

public class FictionBook implements BookInterface {
int height = 0; // height in cm
int pages = 0; // number of pages

/** constructor */
public FictionBook() {
    // TODO Auto-generated constructor stub
}

@Override
public FictionBook setHeight(int height) {
  this.height = height;
  return this;
}

@Override
public FictionBook setPages(int pages) {
  this.pages = pages;
  return this;      
}

@Override
public int getHeight() {
    // TODO Auto-generated method stub
    return height;
}

@Override
public int getPages() {
    // TODO Auto-generated method stub
    return pages;
}

@Override
public String toString(){
    return ("height: " + height + ", " + "pages: " + pages);
}
}

Agora o assinante pode ter associação ao livro:

package com.deepam.hidden;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Subscriber {
BookInterface book;

/** constructor*/
public Subscriber() {
    // TODO Auto-generated constructor stub
}

// injection I
public void setBook(BookInterface book) {
    this.book = book;
}

// injection II
public BookInterface setBook(String bookName) {
    try {
        Class<?> cl = Class.forName(bookName);
        Constructor<?> constructor = cl.getConstructor(); // use it for parameters in constructor
        BookInterface book = (BookInterface) constructor.newInstance();
        //book = (BookInterface) Class.forName(bookName).newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    return book;
}

public BookInterface getBook() {
  return book;
}

public static void main(String[] args) {

}

}

Todas as três classes podem ser ocultadas para sua própria implementação. Agora podemos usar este código para DI:

package com.deepam.implement;

import com.deepam.hidden.Subscriber;
import com.deepam.hidden.FictionBook;

public class CallHiddenImplBook {

public CallHiddenImplBook() {
    // TODO Auto-generated constructor stub
}

public void doIt() {
    Subscriber ab = new Subscriber();

    // injection I
    FictionBook bookI = new FictionBook();
    bookI.setHeight(30); // cm
    bookI.setPages(250);
    ab.setBook(bookI); // inject
    System.out.println("injection I " + ab.getBook().toString());

    // injection II
    FictionBook bookII = ((FictionBook) ab.setBook("com.deepam.hidden.FictionBook")).setHeight(5).setPages(108); // inject and set
    System.out.println("injection II " + ab.getBook().toString());      
}

public static void main(String[] args) {
    CallHiddenImplBook kh = new CallHiddenImplBook();
    kh.doIt();
}
}

Existem muitas maneiras diferentes de como usar a injeção de dependência. É possível combiná-lo com Singleton, etc., mas ainda no básico é somente associação realizada criando atributo de tipo de objeto dentro de outro objeto. A utilidade é única e única no aspecto, esse código, que devemos escrever repetidas vezes, está sempre preparado e pronto para nós. É por isso que a DI é tão intimamente ligada à Inversão de Controle (IoC), o que significa que nosso programa passa a controlar outro módulo em execução, que faz injeções de beans em nosso código. (Cada objeto, que pode ser injetado, pode ser assinado ou considerado como um Bean.) Por exemplo, no Spring, isso é feito criando e inicializando ApplicationContextrecipiente, que faz este trabalho para nós. Nós simplesmente em nosso código criamos o Contexto e invocamos a inicialização dos beans. Nesse momento, a injeção foi feita automaticamente.


O ponto principal da Injeção de Dependência (DI) é manter o código-fonte do aplicativo limpo e estável :

  • limpa do código de inicialização de dependência
  • estável independentemente da dependência usada

Praticamente, todo padrão de design separa as preocupações para fazer alterações futuras afetarem arquivos mínimos.

O domínio específico de DI é a delegação de configuração e inicialização de dependência.

Exemplo: DI com script de shell

Se você ocasionalmente trabalha fora do Java, lembre-se de como sourceé frequentemente usado em muitas linguagens de script (Shell, Tcl, etc., ou mesmo importno Python, usado indevidamente para esse fim).

Considere um dependent.shscript simples :

#!/bin/sh
# Dependent
touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

O script é dependente: ele não será executado com sucesso sozinho ( archive_filesnão está definido).

Você define archive_filesno archive_files_zip.shscript de implementação (usando zipneste caso):

#!/bin/sh
# Dependency
function archive_files {
    zip files.zip "[email protected]"
}

Em vez de source-ing script de implementação diretamente no dependente, você usa um injector.sh"container" que envolve ambos os "componentes":

#!/bin/sh 
# Injector
source ./archive_files_zip.sh
source ./dependent.sh

A archive_files dependência acaba de ser injetada no script dependente .

Você poderia ter injetado dependência que implementa archive_filesusando tarou xz.

Exemplo: removendo DI

Se o dependent.shscript usasse dependências diretamente, a abordagem seria chamada de pesquisa de dependência (que é oposta à injeção de dependência ):

#!/bin/sh
# Dependent

# dependency look-up
source ./archive_files_zip.sh

touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

Agora, o problema é que o "componente" dependente precisa executar a própria inicialização.

O código-fonte do "componente" não é limpo nem estável, porque todas as alterações na inicialização de dependências exigem nova liberação para o arquivo de código-fonte dos "componentes".

Últimas palavras

DI não é amplamente enfatizado e popularizado como em frameworks Java.

Mas é uma abordagem genérica para dividir as preocupações de:

  • desenvolvimento de aplicativos ( ciclo de vida de liberação de código fonte único )
  • Implantação de aplicativo ( vários ambientes de destino com ciclos de vida independentes)

Usar a configuração apenas com a pesquisa de dependência não ajuda, pois o número de parâmetros de configuração pode mudar por dependência (por exemplo, novo tipo de autenticação), bem como o número de tipos de dependências suportados (por exemplo, novo tipo de banco de dados).


Para tornar o conceito de Injeção de Dependência simples de entender. Vamos dar um exemplo de botão para alternar (ligar / desligar) uma lâmpada.

Sem injeção de dependência

O switch precisa saber de antemão com qual bulbo estou conectado (dependência codificada). Assim,

Switch -> PermanentBulb // switch está diretamente conectado à lâmpada permanente, teste não é possível facilmente

Switch(){
PermanentBulb = new Bulb();
PermanentBulb.Toggle();
}

Com injeção de dependência

Switch só sabe que eu preciso ligar / desligar qualquer bulbo é passado para mim. Assim,

Switch -> Bulb1 OU Bulb2 OU NightBulb (dependência injetada)

Switch(AnyBulb){ //pass it whichever bulb you like
AnyBulb.Toggle();
}

Modificando James Exemplo para Switch e Bulb:

public class SwitchTest { 
  TestToggleBulb() { 
    MockBulb mockbulb = new MockBulb(); 

    // MockBulb is a subclass of Bulb, so we can 
    // "inject" it here: 
    Switch switch = new Switch(mockBulb); 

    switch.ToggleBulb(); 
    mockBulb.AssertToggleWasCalled(); 
  } 
}

public class Switch { 
  private Bulb myBulb; 

  public Switch() { 
    myBulb = new Bulb(); 
  } 

  public Switch(Bulb useThisBulbInstead) { 
    myBulb = useThisBulbInstead; 
  } 

  public void ToggleBulb() { 
    ... 
    myBulb.Toggle(); 
    ... 
  } 
}`




terminology