O que é inversão de controle?

1826

Inversão de controle (IoC) pode ser bastante confusa quando é encontrada pela primeira vez.

  1. O que é isso?
  2. Qual problema ele resolve?
  3. Quando é apropriado usar e quando não?
Mike Minutillo
fonte
292
O problema com a maioria dessas respostas é a terminologia usada. O que é um contêiner? Inversão? Dependência? Explique isso em termos leigos, sem grandes palavras.
Kirk.burleson
13
Veja também em Programmers.SE: Por que a Inversão de controle é chamada dessa maneira?
22413 Izkata
8
É Dependency Injection (DI) - ver descrition Martin Fowlers' aqui: martinfowler.com/articles/injection.html#InversionOfControl
Ricardo Sanchez
É um adjetivo, não um substantivo, não é uma coisa, é uma descrição de uma alteração feita no código, onde o controle do fluxo está no delegado, não no contêiner.
Martin Spamer 12/08

Respostas:

1523

Os padrões Inversion of Control (IoC) e Injection Dependency Injection (DI) têm como objetivo remover dependências do seu código.

Por exemplo, diga que seu aplicativo possui um componente de editor de texto e você deseja fornecer a verificação ortográfica. Seu código padrão ficaria assim:

public class TextEditor {

    private SpellChecker checker;

    public TextEditor() {
        this.checker = new SpellChecker();
    }
}

O que fizemos aqui cria uma dependência entre o TextEditore o SpellChecker. Em um cenário de IoC, faríamos algo assim:

public class TextEditor {

    private IocSpellChecker checker;

    public TextEditor(IocSpellChecker checker) {
        this.checker = checker;
    }
}

No primeiro exemplo de código, estamos instanciando SpellChecker( this.checker = new SpellChecker();), o que significa que a TextEditorclasse depende diretamente da SpellCheckerclasse.

No segundo exemplo de código, estamos criando uma abstração tendo a SpellCheckerclasse de dependência na TextEditorassinatura do construtor (não inicializando a dependência na classe). Isso nos permite chamar a dependência e passá-la para a classe TextEditor da seguinte maneira:

SpellChecker sc = new SpellChecker; // dependency
TextEditor textEditor = new TextEditor(sc);

Agora, o cliente que cria a TextEditorclasse tem controle sobre qual SpellCheckerimplementação usar, porque estamos injetando a dependência na TextEditorassinatura.

urini
fonte
50
Bom exemplo claro. No entanto, suponha que, em vez de exigir que a interface ISpellChecker seja passada ao construtor do objeto, a expomos como uma propriedade configurável (ou método SetSpellChecker). Isso ainda constituiria IoC?
devios1
25
chainguy1337 - sim, seria. O uso de setters como esse é chamado de injeção de setter em vez de injeção de construtor (ambas as técnicas de injeção de dependência). IoC é um padrão bastante genérica, mas a injeção de dependência acheives IoC
Jack Ukleja
257
Apesar dos muitos votos positivos, esta resposta está incorreta. Consulte martinfowler.com/articles/injection.html#InversionOfControl . Em particular, observe a parte que diz "Inversão do controle é um termo muito genérico e, portanto, as pessoas o consideram confuso. Como resultado de muita discussão com vários advogados da IoC, decidimos pelo nome Injeção de Dependência".
Rogério
45
Eu concordo com @Rogeria. isso não explica porque é chamado o COI e estou surpreso com o número de votos até ;-)
Aravind Yarram
31
Sou do lado do @Rogerio e do @Pangea. Este pode ser um bom exemplo para injeção de construtor, mas não é uma boa resposta para a pergunta original. O IoC, conforme definido por Fowler , pode ser realizado sem o uso de injeção de qualquer tipo, por exemplo, usando um localizador de serviço ou mesmo uma herança simples.
Mtsz
642

Inversão de controle é o que você obtém quando o programa retorna, por exemplo, como um programa de GUI.

Por exemplo, em um menu da velha escola, você pode ter:

print "enter your name"
read name
print "enter your address"
read address
etc...
store in database

controlando assim o fluxo de interação do usuário.

Em um programa GUI ou algo assim, dizemos:

when the user types in field a, store it in NAME
when the user types in field b, store it in ADDRESS
when the user clicks the save button, call StoreInDatabase

Portanto, agora o controle é invertido ... em vez de o computador aceitar a entrada do usuário em uma ordem fixa, o usuário controla a ordem em que os dados são inseridos e quando os dados são salvos no banco de dados.

Basicamente, qualquer coisa com um loop de eventos, retornos de chamada ou gatilhos de execução se enquadra nessa categoria.

Mark Harrison
fonte
161
Não marque esse cara. tecnicamente, ele está correto martinfowler.com/bliki/InversionOfControl.html IoC é um diretor muito geral. Fluxo de controle é "invertida" por injeção de dependência, porque você efetivamente delegado dependências a algum sistema externo (por exemplo recipiente COI)
Jack Ukleja
38
Concordou com o comentário de Schneider. 5 votos negativos? A mente confunde, já que esta é a única resposta realmente correta. Observe a abertura: ' como um programa de GUI'. A injeção de dependência é apenas a realização mais comum de IoC.
Jeff Sternal
40
De fato, esta é uma das poucas respostas corretas ! Pessoal, a IoC não é fundamentalmente sobre dependências. De modo nenhum.
Rogério
13
+1 - Esta é uma boa descrição (por exemplo) da seguinte declaração de Martin Fowler - "As interfaces de usuário anteriores eram controladas pelo programa aplicativo. Você teria uma sequência de comandos como" Digite o nome "," digite o endereço "; Com as UIs gráficas (ou mesmo baseadas na tela), a estrutura da UI conteria esse loop principal e o seu programa fornecia manipuladores de eventos para os vários campos da tela. o programa foi invertido, mudou-se de você para a estrutura ".
Ashish Gupta
14
Agora eu entendo por que às vezes é jocosamente referido como o "Princípio Hollywood: Não ligue para nós, vamos chamá-lo"
Alexander Suraphel
419

O que é inversão de controle?

Se você seguir estas duas etapas simples, terá feito inversão de controle:

  1. Separar o que -para-fazer parte de quando -a-separe.
  2. Assegure-se de que quando a parte souber o mínimo possível sobre qual parte; e vice versa.

Existem várias técnicas possíveis para cada uma dessas etapas com base na tecnologia / idioma que você está usando para sua implementação.

-

A inversão parte da inversão de controle (COI) é a coisa confundindo; porque inversão é o termo relativo. A melhor maneira de entender a IoC é esquecer essa palavra!

-

Exemplos

  • Manipulação de eventos. Manipuladores de eventos (parte do que fazer) - Gerando eventos (parte do que fazer)
  • Interfaces. Cliente do componente (parte quando fazer) - Implementação da interface do componente (parte que fazer)
  • xUnit. Configuração e TearDown (parte do que fazer) - as estruturas do xUnit chamam a Instalação no início e TearDown no final (parte da tarefa)
  • Modelo método de design padrão. método de modelo parte do que fazer - implementação primitiva da subclasse parte do que fazer
  • Métodos de contêiner DLL em COM. DllMain, DllCanUnload, etc (parte do que fazer) - COM / OS (parte do que fazer)
rpattabi
fonte
Como você está dizendo Interfaces. O cliente componente (parte quando fazer) como "quando" não faz sentido quando usamos interfaces (Ex: Injeção de Dependência), apenas o abstraímos e damos ao cliente flexibilidade para adicionar qualquer implementação, mas não há "quando" envolvido lá. Eu concordo com "when" no caso de Levantar eventos de manipulação de eventos.
OldSchool
Por 'cliente componente', eu quis dizer o usuário / cliente da interface. O cliente sabe 'quando' acionar a parte 'o que fazer' se a intenção é estender a funcionalidade ou não.
Rpattabi 5/05
Dê uma olhada neste maravilhoso artigo de Martin Fowler. Ele mostra como interfaces de fazer a parte fundamental da inversão de controle: martinfowler.com/articles/injection.html#InversionOfControl
rpattabi
duas primeiras frases são brilhantes. impressionante !! separação perfeita com o que fazer e o que fazer !! Eu não sei por que outras respostas recebem tantos votos positivos. eles apenas falam códigos sem nenhum entendimento.
Amir Ziarati
2
Eu gosto da explicação what-to-doewhen-to-do
KimchiMan
164

Inversão de controles é sobre separar preocupações.

Sem IoC : você possui um laptop e acidentalmente interrompe a tela. E, caramba, você encontra o mesmo modelo de tela do laptop em nenhum lugar do mercado. Então você está preso.

Com IoC : você tem uma área de trabalho computador e acidentalmente interrompe a tela. Você descobre que pode pegar praticamente qualquer monitor de mesa do mercado e funciona bem com sua área de trabalho.

Sua área de trabalho implementa com êxito a IoC neste caso. Ele aceita vários tipos de monitores, enquanto o laptop não, ele precisa de uma tela específica para ser consertada.

Luo Jiong Hui
fonte
1
@Luo Jiong Hui Boa explicação.
Sachin
3
A maioria dos padrões de design, se não todos, tem suas contrapartes em nossa vida diária que vemos e entendemos tão bem. A maneira mais eficiente de entender um padrão de design é conhecer seus colegas da vida cotidiana. E acredito que existem muitos.
Luo Jiong Hui,
6
Resposta incorreta. Você está explicando a injeção de dependência e não a IoC. Veja o comentário de Rogério sobre esta resposta acima
MickyD 29/08
2
Concordo. Este é DI, não IoC. Ainda recebe um voto positivo de, porque é uma abordagem simples, mas ajuda a expandir a compreensão do tópico.
Mar
Explica a injeção de dependência. Não Ioc. Mas explicação agradável e clara.
Chamin Wickramarathna
120

Inversão de controle (ou IoC) é sobre obter liberdade (você se casa, você perdeu a liberdade e está sendo controlado. Você se divorciou, acabou de implementar a Inversão de controle. Era isso que chamamos de "desacoplado". Bom sistema de computador desencoraja um relacionamento muito próximo.) mais flexibilidade (a cozinha do seu escritório serve apenas água da torneira, que é a sua única opção quando você deseja beber. Seu chefe implementou a Inversão de Controle instalando uma nova máquina de café. Agora você obtém o flexibilidade de escolher água da torneira ou café.) e menos dependência (seu parceiro tem um emprego, você não tem um emprego, depende financeiramente do seu parceiro, por isso é controlado. Você encontra um emprego, implementou a Inversão de Controle. Bom computador sistema incentiva a dependência.)

Ao usar um computador de mesa, você escrava (ou diz, controla). Você tem que sentar diante de uma tela e olhar para ela. Usando o teclado para digitar e usando o mouse para navegar. E um software mal escrito pode escravizar você ainda mais. Se você substituir sua área de trabalho por um laptop, terá um controle um pouco invertido. Você pode facilmente pegá-lo e se movimentar. Então agora você pode controlar onde está com seu computador, em vez de controlá-lo.

Ao implementar a Inversão de controle, um consumidor de software / objeto obtém mais controles / opções sobre o software / objetos, em vez de ser controlado ou ter menos opções.

Com as idéias acima em mente. Ainda sentimos falta de uma parte essencial da IoC. No cenário de IoC, o consumidor de software / objeto é uma estrutura sofisticada. Isso significa que o código que você criou não é chamado por você. Agora vamos explicar por que dessa maneira funciona melhor para um aplicativo da web.

Suponha que seu código seja um grupo de trabalhadores. Eles precisam construir um carro. Esses trabalhadores precisam de um local e ferramentas (uma estrutura de software) para construir o carro. Uma estrutura de software tradicional será como uma garagem com muitas ferramentas. Portanto, os trabalhadores precisam fazer um plano e usar as ferramentas para construir o carro. Construir um carro não é um negócio fácil, será muito difícil para os trabalhadores planejar e cooperar adequadamente. UMA modernoA estrutura de software será como uma fábrica de carros moderna, com todas as instalações e gerentes instalados. Os trabalhadores não precisam fazer nenhum plano, os gerentes (parte da estrutura, eles são as pessoas mais inteligentes e o plano mais sofisticado) ajudarão a coordenar para que os trabalhadores saibam quando fazer seu trabalho (a estrutura chama seu código). Os funcionários só precisam ser flexíveis o suficiente para usar as ferramentas que os gerentes lhes fornecem (usando a Injeção de Dependência).

Embora os trabalhadores dêem o controle do gerenciamento do projeto no nível superior aos gerentes (a estrutura). Mas é bom ter alguns profissionais ajudando. Este é o conceito de IoC realmente provém.

Os aplicativos modernos da Web com uma arquitetura MVC dependem da estrutura para fazer o roteamento de URL e colocar os controladores no lugar para a estrutura chamar.

Injeção de Dependência e Inversão de Controle estão relacionadas. A injeção de dependência está no nível micro e a inversão de controle está no nível macro . Você deve comer todas as mordidas (implementar DI) para terminar uma refeição (implementar IoC).

Luo Jiong Hui
fonte
21
Votei na comparação entre DI e casamento e IoC com divórcio.
Marek Bar
"Embora os trabalhadores dêem o controle de gerenciar o projeto no nível superior aos gerentes (a estrutura). Mas é bom ter alguns profissionais ajudando. Esse é o conceito de IoC realmente provém." - Em primeiro lugar, o controle é com o gerente. Você pode explicar como esse controle é invertido? Com a ajuda de profissionais (que tipo de profissional)? Como ?
Istiaque Ahmed
@Istiaque Ahmed, comparando com uma garagem onde os trabalhadores têm controle total de tudo, os gerentes das modernas fábricas de automóveis controlam a produção. Então agora os trabalhadores são controlados em vez de controladores. Esteja ciente de que os gerentes, neste contexto, fazem parte da moderna fábrica de automóveis, não dos trabalhadores. Profissionais são os gerentes profissionais no planejamento e fabricação de carros.
Luo Jiong Hui
2
Mensagem para as pessoas casadas: não se divorcie agora, suas classes de filhos também podem implementar a IoC.
Julian
Sim, este a apenas minha visão sobre o casamento também IoC
balron
94

Antes de usar a Inversão de controle, você deve estar ciente do fato de que ela possui seus prós e contras e deve saber por que usá-la se o fizer.

Prós:

  • Seu código é dissociado para que você possa trocar facilmente implementações de uma interface com implementações alternativas
  • É um forte motivador para codificar contra interfaces em vez de implementações
  • É muito fácil escrever testes de unidade para o seu código, porque ele depende apenas dos objetos que ele aceita em seus construtores / setters e você pode inicializá-los facilmente com os objetos certos isoladamente.

Contras:

  • O IoC não apenas inverte o fluxo de controle em seu programa, como também o obscurece consideravelmente. Isso significa que você não pode mais apenas ler seu código e pular de um lugar para outro, porque as conexões que normalmente estariam no seu código não estão mais no código. Em vez disso, está nos arquivos de configuração XML ou nas anotações e no código do seu contêiner de IoC que interpreta esses metadados.
  • Surge uma nova classe de erros em que você configura incorretamente sua configuração XML ou suas anotações e pode gastar muito tempo descobrindo por que seu contêiner IoC injeta uma referência nula em um de seus objetos sob determinadas condições.

Pessoalmente, vejo os pontos fortes da IoC e realmente gosto deles, mas tendem a evitá-la sempre que possível, porque transforma seu software em uma coleção de classes que não constituem mais um programa "real", mas apenas algo que precisa ser reunido por Os metadados de configuração ou anotação XML e desmoronariam (e desmoronariam) sem ele.

ahe
fonte
3
O primeiro golpe está incorreto. Idealmente, deve haver apenas 1 uso do contêiner IOC em seu código, e esse é o seu método principal. Tudo o resto deve cascatear a partir daí
mwjackson
23
Acho que o que ele quer dizer é que você não pode simplesmente ler: myService.DoSomething () e ir para a definição de DoSomething, porque com a IoC, o myService é apenas uma interface e a implementação real é desconhecida para você, a menos que você vá procurar em arquivos de configuração xml ou no método principal em que o seu ioc é configurado.
Chrismay 23/05
7
É aí que o Resharper ajuda - "clique em ir para implementação" na interface. Evitando IoC (ou mais especificamente DI a partir de seu exemplo), provavelmente também significa que você não está testando corretamente
IThasTheAnswer
10
Re: transforma seu software em uma coleção de classes que não constituem mais um programa "real", mas apenas algo que precisa ser montado pelos metadados de configuração ou anotação XML e que desmoronaria (e desmorona) sem ele - acho que isso é muito enganador. O mesmo poderia ser dito de qualquer programa escrito sobre uma estrutura. A diferença com um bom contêiner de IoC é que, se seu programa for bem projetado e gravado, removê-lo e colocá-lo em outro com alterações mínimas no seu código ou jogar fora o IoC completamente e construir seus objetos manualmente .
The Bear Awnry
7
É bom ver uma resposta do mundo real como esta! Eu acho que existem muitos programadores experientes, confortáveis ​​com o design orientado a objetos e práticas de TDD, já usando interfaces, padrões de fábrica, modelos orientados a eventos e zombarias onde faz sentido, antes que este chavão de "IoC" fosse inventado. Infelizmente, muitos desenvolvedores / "arquitetos" reivindicam más práticas se você não usar as estruturas preferidas. Eu prefiro um melhor design, uso de built-in conceitos de linguagem e ferramentas, para alcançar o mesmo objetivo com uma fração da complexidade, ou seja, sem "turvação" a implementação como você diz :-)
Tony Muro
68
  1. Artigo da Wikipedia . Para mim, a inversão de controle está transformando seu código gravado seqüencialmente e transformando-o em uma estrutura de delegação. Em vez de seu programa controlar explicitamente tudo, ele cria uma classe ou biblioteca com determinadas funções a serem chamadas quando certas coisas acontecem.

  2. Resolve a duplicação de código. Por exemplo, antigamente, você escrevia manualmente seu próprio loop de eventos, pesquisando as bibliotecas do sistema para novos eventos. Hoje em dia, nas APIs mais modernas, você simplesmente diz às bibliotecas do sistema em quais eventos você está interessado, e ele será informado quando eles acontecerem.

  3. A inversão do controle é uma maneira prática de reduzir a duplicação de código e, se você copiar um método inteiro e alterar apenas um pequeno pedaço do código, considere enfrentá-lo com inversão de controle. A inversão do controle é facilitada em muitos idiomas através do conceito de delegados, interfaces ou até mesmo ponteiros de funções brutas.

    Não é apropriado usar em todos os casos, porque o fluxo de um programa pode ser mais difícil de seguir quando escrito dessa maneira. É uma maneira útil de projetar métodos ao escrever uma biblioteca que será reutilizada, mas deve ser usada com moderação no núcleo do seu próprio programa, a menos que realmente resolva um problema de duplicação de código.

NilObject
fonte
37
Acho esse artigo da Wikipedia muito confuso e com necessidade de conserto. Confira a página de discussão para rir.
devios1
Escrever seu próprio loop de eventos ainda pode ser uma inversão de controle, se esse loop de eventos substituir o quadro e o restante do código estiver usando o princípio IoC, você acabou de escrever seu próprio framework. Na verdade, isso não é uma coisa ruim, pois aumenta a legibilidade ao preço de apenas um pouco mais de codificação (não que seja sempre apropriado também).
lijat
45

Mas acho que você precisa ter muito cuidado com isso. Se você usar demais esse padrão, criará um design muito complicado e um código ainda mais complicado.

Como neste exemplo com o TextEditor: se você tiver apenas um SpellChecker, talvez não seja realmente necessário usar a IoC? A menos que você precise escrever testes de unidade ou algo assim ...

De qualquer forma: seja razoável. Padrão de design são boas práticas, mas não a Bíblia a ser pregada. Não cole em todos os lugares.

Michal Sznajder
fonte
3
Como você sabe que terá apenas um corretor ortográfico?
Rastreie
@ Trace Você pode saber como o programa que você vai escrever será usado, por exemplo. Ainda algumas técnicas, como a injeção de dependência, são tão baratas que raramente há uma razão para não usá-las em um caso como esse.
lijat
44

IoC / DI para mim está enviando dependências para os objetos que estão chamando. Super simples.

A resposta não-techy é ser capaz de trocar um motor em um carro antes de ligá-lo. Se tudo estiver certo (a interface), você estará bem.

ferventcoder
fonte
44

Suponha que você seja um objeto. E você vai a um restaurante:

Sem IoC : você pede "maçã" e sempre recebe maçã quando pede mais.

Com IoC : você pode pedir "fruta". Você pode obter frutas diferentes cada vez que for servido. por exemplo, maçã, laranja ou melancia.

Portanto, obviamente, a IoC é preferida quando você gosta das variedades.

Luo Jiong Hui
fonte
26
  1. Inversão de controle é um padrão usado para desacoplar componentes e camadas no sistema. O padrão é implementado através da injeção de dependências em um componente quando ele é construído. Essas dependências geralmente são fornecidas como interfaces para dissociação adicional e para suportar a testabilidade. Os contêineres IoC / DI, como Castle Windsor, Unity, são ferramentas (bibliotecas) que podem ser usadas para fornecer IoC. Essas ferramentas fornecem recursos estendidos acima e além do simples gerenciamento de dependências, incluindo vida útil, AOP / interceptação, política etc.

  2. uma. Evita que um componente seja responsável por gerenciar suas dependências.
    b. Fornece a capacidade de trocar implementações de dependência em diferentes ambientes.
    c. Permite que um componente seja testado através da simulação de dependências.
    d. Fornece um mecanismo para compartilhar recursos em um aplicativo.

  3. uma. Crítico ao fazer desenvolvimento orientado a teste. Sem a IoC, pode ser difícil testar, porque os componentes em teste são altamente acoplados ao restante do sistema.
    b. Crítico ao desenvolver sistemas modulares. Um sistema modular é um sistema cujos componentes podem ser substituídos sem a necessidade de recompilação.
    c. Crítico se houver muitas preocupações transversais que precisam ser abordadas, compartilhadas em um aplicativo corporativo.

Glenn Block
fonte
2
Na verdade, a IoC não se refere principalmente ao gerenciamento de dependências. Consulte martinfowler.com/articles/injection.html#InversionOfControl Em particular, observe a parte que diz "Inversão de controle é um termo muito genérico e, portanto, as pessoas o acham confuso. Como resultado de muita discussão com vários advogados de IoC, estabelecido no nome Injection Dependency ".
Rogério
26

Respondendo apenas a primeira parte. O que é isso?

Inversão de controle (IoC) significa criar instâncias de dependências primeira e última instância de uma classe (opcionalmente injetando-as por meio do construtor), em vez de criar uma instância da classe primeiro e depois a instância da classe criando instâncias de dependências. Assim, a inversão de controle inverte o fluxo de controle do programa. Em vez de o receptor controlar o fluxo de controle (enquanto cria dependências), o chamador controla o fluxo de controle do programa .

user2330678
fonte
A sua não é sobre a classe ou a criação de objetos, verifique este martinfowler.com/articles/injection.html#InversionOfControl
Raghvendra Singh
22

Escreverei minha compreensão simples desses dois termos:

For quick understanding just read examples*

Injeção de Dependência (DI):
injeção de dependência geralmente significa passar um objeto do qual o método depende, como parâmetro para um método, em vez de fazer com que o método crie o objeto dependente .
O que isso significa na prática é que o método não depende diretamente de uma implementação específica; qualquer implementação que atenda aos requisitos pode ser passada como parâmetro.

Com isso, conte suas dependências. E a primavera a disponibiliza.
Isso leva ao desenvolvimento de aplicativos fracamente acoplados.

Quick Example:EMPLOYEE OBJECT WHEN CREATED,
              IT WILL AUTOMATICALLY CREATE ADDRESS OBJECT
   (if address is defines as dependency by Employee object)

Contêiner de Inversão de Controle (IoC):
Essa é uma característica comum das estruturas, o IOC gerencia objetos java
- da instanciação à destruição através de seu BeanFactory.
-Os componentes Java instanciados pelo contêiner de IoC são chamados de beans, e o contêiner de IoC gerencia o escopo de um bean, eventos de ciclo de vida e quaisquer recursos de AOP para os quais foi configurado e codificado.

QUICK EXAMPLE:Inversion of Control is about getting freedom, more flexibility, and less dependency. When you are using a desktop computer, you are slaved (or say, controlled). You have to sit before a screen and look at it. Using keyboard to type and using mouse to navigate. And a bad written software can slave you even more. If you replaced your desktop with a laptop, then you somewhat inverted control. You can easily take it and move around. So now you can control where you are with your computer, instead of computer controlling it.

Ao implementar a Inversão de controle, um consumidor de software / objeto obtém mais controles / opções sobre o software / objetos, em vez de ser controlado ou ter menos opções.

A inversão do controle como uma diretriz de design serve aos seguintes propósitos:

Há um desacoplamento da execução de uma determinada tarefa da implementação.
Cada módulo pode se concentrar no que foi projetado.
Os módulos não fazem suposições sobre o que outros sistemas fazem, mas dependem de seus contratos.
Substituir módulos não tem efeito colateral em outros módulos.
Vou manter as coisas abstratas aqui. Você pode visitar os links a seguir para entender detalhes do tópico.
Uma boa leitura com exemplo

Explicação detalhada

VdeX
fonte
17

Eu concordo com o NilObject , mas gostaria de acrescentar a isso:

se você estiver copiando um método inteiro e alterando apenas um pequeno pedaço do código, considere enfrentá-lo com inversão de controle

Se você está copiando e colando códigos, quase sempre está fazendo algo errado. Codificado como o princípio do design Uma vez e Apenas uma vez .

Peter Burns
fonte
17

Por exemplo, a tarefa 1 é criar objeto. Sem o conceito de COI, a tarefa 1 deve ser executada pelo programador, mas com o conceito de COI, a tarefa 1 será feita por contêiner.

Em resumo, o controle é invertido do programador para o contêiner. Então, isso é chamado de inversão de controle.

Encontrei um bom exemplo aqui .

gogs
fonte
Um contêiner é um conceito em IoC onde o modelo de objeto, incluindo dependências (relacionamentos entre o objeto "usuário" e o objeto "usado") e instâncias de objetos, residem e são gerenciados - por exemplo, contidos. O contêiner geralmente é fornecido por uma estrutura de IoC, como o Spring. Pense nisso como um repositório de tempo de execução para os objetos que compõem seu aplicativo.
The Bear Awnry
17

Digamos que nos reunimos em algum hotel.

Muitas pessoas, muitas garrafas de água, muitos copos de plástico.

Quando alguém quer beber, ela enche a xícara, bebe e joga a xícara no chão.

Depois de uma hora ou algo assim, temos um piso coberto de copos de plástico e água.

Deixe o controle invertido.

A mesma reunião no mesmo lugar, mas em vez de copos de plástico, temos um garçom com um copo de vidro (Singleton)

e ela sempre oferece aos convidados que bebem.

Quando alguém quer beber, ela pega o copo de garçom, bebe e devolve ao garçom.

Deixando de lado a questão da última forma higiênica de controle do processo de beber é muito mais eficaz e econômica.

E é exatamente isso que o Spring (outro contêiner de IoC, por exemplo: Guice) faz. Em vez de permitir que o aplicativo crie o que é necessário usando a nova palavra-chave (copo de plástico), o contêiner Spring IoC oferece sempre o aplicativo da mesma instância (singleton) do objeto necessário (copo de água).

Pense em si mesmo como organizador dessa reunião. Você precisa enviar uma mensagem à administração do hotel que

os membros da reunião precisarão de um copo de água, mas não de um pedaço de bolo.

Exemplo:-

public class MeetingMember {

    private GlassOfWater glassOfWater;

    ...

    public void setGlassOfWater(GlassOfWater glassOfWater){
        this.glassOfWater = glassOfWater;
    }
    //your glassOfWater object initialized and ready to use...
    //spring IoC  called setGlassOfWater method itself in order to
    //offer to meetingMember glassOfWater instance

}

Links Úteis:-

Jainendra
fonte
não são objetos de tipo estático de singletons?
Gokigooooks
16

Parece que a coisa mais confusa em "IoC", o acrônimo e o nome pelo qual ele representa, é que é um nome muito glamouroso - quase um nome barulhento.

Nós realmente precisamos de um nome para descrever a diferença entre programação procedural e orientada a eventos? OK, se precisarmos, mas precisamos escolher um novo nome "maior que a vida" que confunda mais do que resolve?

email.privacy
fonte
1
IoC! = Orientado a eventos. As semelhanças (e em alguns casos se sobrepõem), mas não são principalmente o mesmo paradigma.
The Bear Awnry
Boa pergunta. A programação orientada a eventos é certamente IoC. Nós escrevemos manipuladores de eventos e eles são chamados a partir do loop de eventos. Porém, IoC é um conceito mais genérico que a programação orientada a eventos. Se você substituir um método na subclasse, também será um tipo de IoC. Você escreve um código que seria chamado quando a referência apropriada (instância) fosse usada.
vi.su.
15

Inversão de controle é quando você vai ao supermercado e sua esposa fornece a lista de produtos a serem comprados.

Em termos de programação, ela passou uma função de retorno de chamada getProductList()para a função que você está executando - doShopping().

Ele permite que o usuário da função defina algumas partes dela, tornando-a mais flexível.

Sergiy Ostrovsky
fonte
5
Minha esposa geralmente compra comigo, mas eu concordo com essa afirmação.
ha9u63ar
1
@ ha9u63ar Sua esposa faz compras com você? Bem, isso é chamado de agregação então.
Julian
2
Se ela também der o dinheiro, isso se chama DI.
San
1
A palavra Inversão - de cabeça para baixo - veio, quando sua esposa liga, getProductList()você precisa encontrar a fonte do dinheiro, significa que o controle está ao seu lado. No caso de inversão, ela controlará, significa também o dinheiro que fornecerá para comprar.
San
13

Encontrei um exemplo muito claro aqui que explica como o 'controle é invertido'.

Código clássico (sem injeção de dependência)

Aqui está como um código que não usa DI funcionará aproximadamente:

  • A aplicação precisa de Foo (por exemplo, um controlador), portanto:
  • Aplicativo cria Foo
  • Aplicativo chama Foo
    • Foo precisa de Bar (por exemplo, um serviço), então:
    • Foo cria Bar
    • Foo chama Bar
      • Bar precisa do Bim (um serviço, um repositório,…), então:
      • Bar cria Bim
      • Bar faz alguma coisa

Usando injeção de dependência

Aqui está como um código usando DI funcionará aproximadamente:

  • O aplicativo precisa de Foo, que precisa de Bar, que precisa de Bim, então:
  • Aplicativo cria Bim
  • Aplicativo cria Bar e fornece Bim
  • Aplicativo cria Foo e fornece barra
  • Aplicativo chama Foo
    • Foo chama Bar
      • Bar faz alguma coisa

O controle das dependências é invertido de um que está sendo chamado para aquele que está chamando.

Que problemas ele resolve?

A injeção de dependência facilita a troca com a implementação diferente das classes injetadas. Durante o teste de unidade, você pode injetar uma implementação fictícia, o que facilita muito o teste.

Ex: suponha que seu aplicativo armazene o arquivo enviado pelo usuário no Google Drive; com o DI, o código do seu controlador pode ficar assim:

class SomeController
{
    private $storage;

    function __construct(StorageServiceInterface $storage)
    {
        $this->storage = $storage;
    }

    public function myFunction () 
    {
        return $this->storage->getFile($fileName);
    }
}

class GoogleDriveService implements StorageServiceInterface
{
    public function authenticate($user) {}
    public function putFile($file) {}
    public function getFile($file) {}
}

Quando seus requisitos mudam, digamos, em vez do GoogleDrive, você é solicitado a usar o Dropbox. Você só precisa escrever uma implementação de caixa de depósito para o StorageServiceInterface. Você não faz nenhuma alteração no controlador, desde que a implementação do Dropbox siga o StorageServiceInterface.

Durante o teste, você pode criar a simulação para o StorageServiceInterface com a implementação fictícia em que todos os métodos retornam nulos (ou qualquer valor predefinido conforme o requisito de teste).

Em vez disso, se você tivesse a classe controller para construir o objeto de armazenamento com a newpalavra - chave desta forma:

class SomeController
{
    private $storage;

    function __construct()
    {
        $this->storage = new GoogleDriveService();
    }

    public function myFunction () 
    {
        return $this->storage->getFile($fileName);
    }
}

Quando você deseja alterar a implementação do Dropbox, substitua todas as linhas em que new objeto GoogleDriveService é construído e use o DropboxService. Além disso, ao testar a classe SomeController, o construtor sempre espera a classe GoogleDriveService e os métodos reais dessa classe são acionados.

Quando é apropriado e quando não? Na minha opinião, você usa DI quando pensa que há (ou pode haver) implementações alternativas de uma classe.

Raghavendra N
fonte
Essa deve ser a resposta mais correta, pois é a única que explica como o "controle" é invertido.
Yarimadam 15/11
melhor explicação até agora
Ali80 23/02
12

Uma explicação escrita muito simples pode ser encontrada aqui

http://binstock.blogspot.in/2008/01/excellent-explanation-of-dependency.html

Diz -

"Qualquer aplicativo não trivial é composto de duas ou mais classes que colaboram entre si para executar alguma lógica de negócios. Tradicionalmente, cada objeto é responsável por obter suas próprias referências aos objetos com os quais colabora (suas dependências). Ao aplicar o DI, o objetos recebem suas dependências no momento da criação por alguma entidade externa que coordena cada objeto no sistema. Em outras palavras, as dependências são injetadas nos objetos ".

de novo
fonte
12

Inversão de controle é um princípio genérico, enquanto a injeção de dependência realiza esse princípio como um padrão de design para a construção de gráficos de objetos (ou seja, a configuração controla como os objetos se referenciam uns aos outros, em vez de o próprio objeto controlar como obter a referência para outro objeto).

Olhando Inversão de Controle como um padrão de design, precisamos olhar para o que estamos invertendo. A injeção de dependência inverte o controle da construção de um gráfico de objetos. Se contada no termo leigo, a inversão de controle implica mudança no fluxo de controle no programa. Por exemplo. No aplicativo independente tradicional, temos o método principal, de onde o controle é passado para outras bibliotecas de terceiros (no caso, usamos a função de biblioteca de terceiros), mas, através da inversão do controle, o controle é transferido do código da biblioteca de terceiros para o nosso código , como estamos recebendo o serviço de uma biblioteca de terceiros. Mas há outros aspectos que precisam ser invertidos dentro de um programa - por exemplo, invocação de métodos e threads para executar o código.

Para os interessados ​​em mais detalhes sobre a Inversão de controle, foi publicado um artigo descrevendo uma imagem mais completa da Inversão de controle como padrão de design (OfficeFloor: usando padrões de escritório para melhorar o design de software http://doi.acm.org/10.1145/ 2739011.2739013 com uma cópia gratuita disponível para download em http://www.officefloor.net/about.html ).

O que é identificado é o seguinte relacionamento:

Inversão de controle (para métodos) = Injeção de dependência (estado) + Injeção de continuação + Injeção de rosca

Resumo do relacionamento acima para Inversão de controle disponível - http://dzone.com/articles/inversion-of-coupling-control

Daniel Sagenschneider
fonte
Esta é uma resposta muito clara. Obrigada pelo esclarecimento.
KunYu Tsai
11

IoC trata-se de inverter o relacionamento entre seu código e o código de terceiros (biblioteca / estrutura):

  • No desenvolvimento s / w normal, você escreve o método main () e chama os métodos "library". Você está no controle :)
  • Na IoC, o "framework" controla main () e chama seus métodos. O Framework está no controle :(

DI (Injection Dependency) é sobre como o controle flui no aplicativo. O aplicativo de área de trabalho tradicional tinha fluxo de controle do seu aplicativo (método main ()) para outras chamadas de método de biblioteca, mas com o fluxo de controle de DI invertido, a estrutura cuida de iniciar seu aplicativo, inicializando-o e invocando seus métodos sempre que necessário.

No final, você sempre vence :)

Khanh
fonte
10

Eu gosto desta explicação: http://joelabrahamsson.com/inversion-of-control-an-introduction-with-examples-in-net/

Começa simples e mostra exemplos de código também.

insira a descrição da imagem aqui

O consumidor, X, precisa da classe consumida, Y, para realizar alguma coisa. Tudo isso é bom e natural, mas X realmente precisa saber que usa Y?

Não basta que X saiba que usa algo que possui o comportamento, os métodos, as propriedades etc. de Y sem saber quem realmente implementa o comportamento?

Ao extrair uma definição abstrata do comportamento usado por X em Y, ilustrado como abaixo, e permitir que o consumidor X use uma instância disso em vez de Y, ele pode continuar fazendo o que faz sem precisar conhecer as especificidades sobre Y.

insira a descrição da imagem aqui

Na ilustração acima, Y implementa I e X usa uma instância de I. Embora seja bem possível que X ainda use Y, o interessante é que X não sabe disso. Só sabe que usa algo que implementa I.

Leia o artigo para obter mais informações e descrição de benefícios, como:

  • X não depende mais de Y
  • Mais flexível, a implementação pode ser decidida em tempo de execução
  • Isolamento da unidade de código, teste mais fácil

...

DDan
fonte
O link é muito útil. Really Thanks :) #
M Fuat NUROĞLU
10

Entendo que a resposta já foi dada aqui. Mas ainda penso que algumas noções básicas sobre a inversão de controle precisam ser discutidas aqui em detalhes para futuros leitores.

A Inversão de Controle (IoC) foi construída com base em um princípio muito simples chamado Princípio de Hollywood . E diz isso,

Não ligue para nós, nós ligaremos para você

O que isso significa é que não vá a Hollywood para realizar seu sonho; se você é digno, Hollywood o encontrará e fará com que seu sonho se torne realidade. Quase invertido, não é?

Agora, quando discutimos sobre o princípio da IoC, costumamos esquecer o Hollywood. Para a IoC, tem que haver três elementos: um Hollywood, você e uma tarefa como realizar o seu sonho.

No nosso mundo da programação, Hollywood representa uma estrutura genérica (pode ser escrita por você ou outra pessoa), você representa o código do usuário que você escreveu e a tarefa representa o que você deseja realizar com o seu código. Agora você nunca inicia sua tarefa sozinho, não na IoC! Em vez disso, você projetou tudo para que sua estrutura inicie sua tarefa. Assim, você construiu uma estrutura reutilizável que pode transformar alguém em herói ou outro em vilão. Mas essa estrutura está sempre no comando, sabe quando escolher alguém e que alguém sabe apenas o que quer ser.

Um exemplo da vida real seria dado aqui. Suponha que você deseje desenvolver um aplicativo da web. Portanto, você cria uma estrutura que lida com todas as coisas comuns que um aplicativo Web deve lidar, como lidar com solicitações http, criar menu de aplicativos, exibir páginas, gerenciar cookies, acionar eventos etc.

E então você deixa alguns ganchos em sua estrutura, onde pode colocar mais códigos para gerar menus personalizados, páginas, cookies ou registrar alguns eventos do usuário etc. para o navegador.

Então, a ideia é bastante simples. Em vez de criar um aplicativo de usuário que controla tudo, primeiro você cria uma estrutura reutilizável que controla tudo e depois escreve seus códigos personalizados e conecta-os à estrutura para executá-los a tempo.

Laravel e EJB são exemplos de tais estruturas.

Referência:

https://martinfowler.com/bliki/InversionOfControl.html

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

Abdullah Al Farooq
fonte
1
A resposta mais apropriada que encontrei aqui.
blueray
8

Falando de programação

IoC em termos fáceis: é o uso da Interface como uma maneira específica de algo (como um campo ou parâmetro) como um curinga que pode ser usado por algumas classes. Permite a reutilização do código.

Por exemplo, digamos que temos duas classes: Cão e Gato . Ambos compartilham as mesmas qualidades / estados: idade, tamanho, peso. Portanto, em vez de criar uma classe de serviço chamada DogService e CatService , posso criar uma única chamada AnimalService que permita o uso de Dog and Cat somente se eles usarem a interface IAnimal .

No entanto, pragmaticamente falando, tem alguns retrocessos.

a) A maioria dos desenvolvedores não sabe como usá-lo . Por exemplo, eu posso criar uma classe chamada Customer e posso criar automaticamente (usando as ferramentas do IDE) uma interface chamada ICustomer . Portanto, não é raro encontrar uma pasta cheia de classes e interfaces, independentemente de as interfaces serem reutilizadas ou não. É chamado FLUTUADO. Algumas pessoas podem argumentar que "pode ​​ser que no futuro possamos usá-lo". : - |

b) Tem alguns limites. Por exemplo, vamos falar sobre o caso de Dog and Cat e eu quero adicionar um novo serviço (funcionalidade) apenas para cães. Digamos que eu quero calcular o número de dias que preciso para treinar um cachorro ( trainDays()), pois gato é inútil, gatos não podem ser treinados (estou brincando).

b.1) Se eu adicionar trainDays()ao Service AnimalService , ele também funciona com gatos e não é válido.

b.2) Posso adicionar uma condição em trainDays()que avalia qual classe é usada. Mas isso quebrará completamente a IoC.

b.3) Posso criar uma nova classe de serviço chamada DogService apenas para a nova funcionalidade. Porém, aumentará a capacidade de manutenção do código, pois teremos duas classes de serviço (com funcionalidade semelhante) para o Dog e isso é ruim.

Magallanes
fonte
Sobre classes / interfaces inchadas: nem sempre é necessário reutilizar todas as interfaces. Às vezes, faz sentido dividir uma interface grande em muitas menores para ver seus limites funcionais. Interfaces menores também são mais fáceis de reutilizar em outras implementações. Também o encoraja a codificar para uma interface onde quer que faça sentido. Considere "Segregação de interface". Só porque você está usando uma interface não significa que você está desacoplado. Uma única interface gorda é inútil. - Apenas meus 2 centavos :) #
313 MK
7

Eu já li muitas respostas para isso, mas se alguém ainda está confuso e precisa de um termo "ultra-leigo" para explicar a IoC, aqui está minha opinião:

Imagine pais e filhos conversando entre si.

Sem IoC:

* Pai : Você só pode falar quando eu fizer perguntas e você só pode agir quando eu der permissão.

Pai : Isso significa que você não pode me perguntar se pode comer, brincar, ir ao banheiro ou até dormir se eu não perguntar.

Pai : Você quer comer?

Criança : Não.

Pai : Ok, eu volto. Espere por mim.

Criança : (Quer brincar, mas como não há perguntas dos pais, a criança não pode fazer nada).

Após 1 hora...

Pai : estou de volta. Você quer jogar?

Criança : Sim.

Pai : Permissão concedida.

Criança : (finalmente é capaz de brincar).

Este cenário simples explica que o controle está centralizado no pai. A liberdade da criança é restrita e depende muito da pergunta dos pais. A criança SOMENTE pode falar quando for solicitada a falar e SOMENTE pode agir quando tiver permissão.

Com IoC:

A criança agora tem a capacidade de fazer perguntas e os pais podem responder com respostas e permissões. Simplesmente significa que o controle está invertido! A criança agora está livre para fazer perguntas a qualquer momento e, embora ainda exista dependência dos pais em relação às permissões, ela não depende dos meios de falar / fazer perguntas.

De uma maneira tecnológica de explicar, isso é muito semelhante à interação console / shell / cmd x GUI. (Qual é a resposta de Mark Harrison acima da resposta superior no.2). No console, você depende do que está sendo solicitado / exibido e não pode pular para outros menus e recursos sem responder à pergunta primeiro; seguindo um fluxo seqüencial estrito. (programaticamente, isso é como um loop de método / função). No entanto, com a GUI, os menus e os recursos são definidos e o usuário pode selecionar o que for necessário, tendo mais controle e menos restrições. (programaticamente, os menus têm retorno de chamada quando selecionados e uma ação ocorre).

Reuben JaMes Aveño Gruta
fonte
6

Inversão de controle é sobre a transferência de controle da biblioteca para o cliente. Faz mais sentido quando falamos de um cliente que injeta (passa) um valor de função (expressão lambda) em uma função de ordem superior (função de biblioteca) que controla (altera) o comportamento da função de biblioteca. Um cliente ou estrutura que injeta dependências de bibliotecas (que carregam comportamento) nas bibliotecas também pode ser considerado IoC

Sergiu Starciuc
fonte
5

Como já existem muitas respostas para a pergunta, mas nenhuma delas mostra o detalhamento do termo Controle de Inversão, vejo uma oportunidade de fornecer uma resposta mais concisa e útil.

Inversão de controle é um padrão que implementa o princípio de inversão de dependência (DIP). O DIP declara o seguinte: 1. Os módulos de alto nível não devem depender dos módulos de baixo nível. Ambos devem depender de abstrações (por exemplo, interfaces). 2. As abstrações não devem depender de detalhes. Detalhes (implementações concretas) devem depender de abstrações.

Existem três tipos de inversão de controle:

Provedores de inversão de interface não devem definir uma interface. Em vez disso, o consumidor deve definir a interface e os fornecedores devem implementá-la. A Inversão da interface permite eliminar a necessidade de modificar o consumidor sempre que um novo provedor é adicionado.

Inversão do fluxo Altera o controle do fluxo. Por exemplo, você tem um aplicativo de console no qual solicitou a inserção de vários parâmetros e, após cada parâmetro inserido, é forçado a pressionar Enter. Você pode aplicar o Flow Inversion aqui e implementar um aplicativo de desktop em que o usuário possa escolher a sequência de entrada dos parâmetros, editar os parâmetros e, na etapa final, o usuário precisará pressionar Enter apenas uma vez.

Inversão de criação Pode ser implementado pelos seguintes padrões: Padrão de fábrica, Localizador de serviço e Injeção de dependência. Inversão de criação ajuda a eliminar dependências entre tipos, movendo o processo de criação de objetos de dependência para fora do tipo que usa esses objetos de dependência. Por que dependências são ruins? Aqui estão alguns exemplos: a criação direta de um novo objeto no seu código torna o teste mais difícil; é impossível alterar referências em assembléias sem recompilação (violação do princípio da OCP); você não pode substituir facilmente uma interface do usuário da área de trabalho por uma interface da web.

Vadim S.
fonte
3
  1. Então, número 1 acima . O que é inversão de controle?

  2. Manutenção é a primeira coisa que resolve para mim. Garante que estou usando interfaces para que duas classes não sejam íntimas uma da outra.

Ao usar um contêiner como o Castle Windsor, ele resolve os problemas de manutenção ainda melhor. Ser capaz de trocar um componente que vai para um banco de dados por outro que usa persistência baseada em arquivo sem alterar uma linha de código é impressionante (alteração de configuração, pronto).

E quando você entra em genéricos, fica ainda melhor. Imagine ter um editor de mensagens que recebe registros e publica mensagens. Ele não se importa com o que publica, mas precisa de um mapeador para levar algo de um registro para uma mensagem.

public class MessagePublisher<RECORD,MESSAGE>
{
    public MessagePublisher(IMapper<RECORD,MESSAGE> mapper,IRemoteEndpoint endPointToSendTo)
    {
      //setup
    }
}

Escrevi uma vez, mas agora posso injetar muitos tipos nesse conjunto de códigos se publicar diferentes tipos de mensagens. Também posso escrever mapeadores que registram o mesmo tipo e os mapeiam para mensagens diferentes. O uso do DI com genéricos me deu a capacidade de escrever muito pouco código para realizar muitas tarefas.

Ah, sim, existem preocupações com a testabilidade, mas são secundárias aos benefícios da IoC / DI.

Definitivamente, estou amando IoC / DI.

3) Torna-se mais apropriado no minuto em que você tem um projeto de tamanho médio com um pouco mais de complexidade. Eu diria que isso se torna apropriado no minuto em que você começa a sentir dor.

ferventcoder
fonte
3

Criar um objeto dentro da classe é chamado de acoplamento rígido, o Spring remove essa dependência seguindo um padrão de design (DI / IOC). Em qual objeto da classe passou no construtor em vez de criar na classe. Além disso, damos uma variável de referência de superclasse no construtor para definir uma estrutura mais geral.

shA.t
fonte