Por que a Inversão de controle é chamada dessa maneira?

98

As palavras invertou controlnão são usadas para definir Inversão de Controle nas definições que eu já vi.

Definições

Wikipedia

inversão de controle (IoC) é uma técnica de programação, expressa aqui em termos de programação orientada a objetos, na qual o acoplamento de objetos é vinculado em tempo de execução por um objeto montador e normalmente não é conhecido em tempo de compilação usando análise estática. ~ http://en.wikipedia.org/wiki/Inversion_of_control

Martin Fowler

Inversão de controle é um padrão comum na comunidade Java que ajuda a conectar contêineres leves ou montar componentes de diferentes projetos em um aplicativo coeso. ~ com base em http://www.martinfowler.com/articles/injection.html (reformulado)


Então, por que Inversão de controle é chamada de Inversão de controle? Que controle está sendo invertido e por quê? Existe uma maneira de definir Inversão de Controle usando a terminologia: inverter e controlar ?

Korey Hinton
fonte
22
Suportes para a pessoa que pode explicar isso em inglês simples.
22713 Robert Harvey
2
Se uma definição usasse a palavra que estava definindo, isso seria uma falha de um dicionário. Lógica semelhante se aplica aqui.
22413 Izkata
2
Veja também no StackOverflow: O que é inversão de controle?
22713 Izkata
2
@ Izkata, é muito comum que os dicionários definam frases em termos dos próprios termos ou termos sinônimos. ou seja: a definição de força da natureza usa as palavras força e natureza em sua definição ou a definição de termos de serviço usa as palavras regras e serviço em que regras é sinônimo de termos.
Korey Hinton
3
Prefiro usar o termo "injeção de dependência automatizada" ou ADI em vez de IoC, por esse motivo; O próprio Fowler menciona que a maioria dos paradigmas atuais em programação tem algum tipo de "inversão de controle", em que esse termo é definido geralmente como "o reinício das determinações do código a ser executado e o horário em que ele deve ser executado para um agente externo". sistema de controle, quando tais determinações são tradicionalmente feitas pelo próprio programa ". Tudo, desde interrupções de hardware até programação orientada a eventos, máquinas virtuais e multitarefa, acontece com a IoC.
Keiths

Respostas:

67

Digamos que você tenha algum tipo de classe "repositório", e esse repositório é responsável por entregar dados a você a partir de uma fonte de dados.

O repositório pode estabelecer uma conexão com a fonte de dados por si só. Mas e se isso permitisse que você transmitisse uma conexão à fonte de dados através do construtor do repositório?

Ao permitir que o chamador forneça a conexão, você separou a dependência da conexão da fonte de dados da classe do repositório, permitindo que qualquer fonte de dados funcione com o repositório, não apenas aquela especificada pelo repositório.

Você inverteu o controle , entregando a responsabilidade de criar a conexão da classe do repositório para o chamador.

Martin Fowler sugere usar o termo "Injeção de Dependência" para descrever esse tipo de Inversão de Controle, uma vez que Inversão de Controle como um conceito pode ser aplicado de maneira mais ampla do que apenas injetar dependências em um método construtor.

Robert Harvey
fonte
3
Este é um exemplo de injeção de dependência, mas a injeção de dependência é apenas um subconjunto de inversão de controle. Há outras coisas totalmente não relacionadas à injeção de dependência que praticam inversão de controle.
dsw88
1
@ mustang2009cobra: Obrigado. Um exemplo é o que eu procurava, não um catálogo abrangente de instâncias em que ocorre, e o termo "Inversão de controle" está mais intimamente associado à DI, não à passagem de mensagens ou outros conceitos semelhantes.
Robert Harvey
É verdade que a injeção de dependência é o exemplo mais prevalente de IoC; portanto, um exemplo de DI faz mais sentido. Talvez uma pequena alteração na sua resposta especifique que este é um exemplo de DI, que é o tipo mais proeminente de IoC?
dsw88
1
Era exatamente isso que eu estava procurando! Muitos exemplos e definições de IoC não especificam claramente qual controle está sendo invertido. Eu percebo que pode haver mais na IoC do que apenas injeção de dependência, mas agora algo finalmente clicou no meu cérebro. Obrigado!
Korey Hinton
79

Não acho que alguém possa explicar melhor do que Martin Fowler, mais abaixo no artigo ao qual você vinculou .

Para esta nova geração de contêineres, a inversão é sobre como eles pesquisam uma implementação de plug-in. No meu exemplo ingênuo, o lister procurou a implementação do localizador, instanciando-a diretamente. Isso impede que o localizador seja um plugin. A abordagem usada por esses contêineres é garantir que qualquer usuário de um plug-in siga alguma convenção que permita que um módulo assembler separado injete a implementação na lista.

Como ele explica nos parágrafos acima, isso não é exatamente o mesmo que a razão pela qual o termo "Inversão de controle" se originou.

Quando esses contêineres falam sobre como são tão úteis porque implementam "Inversão de controle", fico muito confuso. Inversão de controle é uma característica comum das estruturas, portanto, dizer que esses contêineres leves são especiais porque usam inversão de controle é como dizer que meu carro é especial porque tem rodas.

A questão é: que aspecto do controle eles estão invertendo? Quando entrei na inversão de controle, ele estava no controle principal de uma interface de usuário. As interfaces de usuário iniciais eram controladas pelo programa aplicativo. Você teria uma sequência de comandos como "Digite o nome", "digite o endereço"; seu programa direcionaria os prompts e receberia uma resposta para cada um. Com interfaces gráficas (ou mesmo baseadas na tela), a estrutura da interface do usuário conteria esse loop principal e seu programa forneceria manipuladores de eventos para os vários campos da tela. O controle principal do programa foi invertido, afastado de você para o framework.

É por isso que ele cunhou o termo "Injeção de Dependência" para cobrir essa implementação específica da Inversão de Controle.

Como resultado, acho que precisamos de um nome mais específico para esse padrão. Inversão de controle é um termo genérico demais e, portanto, as pessoas o consideram confuso. Como resultado, com muita discussão com vários advogados da IoC, decidimos pelo nome Injeção de Dependência.

Para esclarecer um pouco: Inversão de controle significa qualquer coisa que inverta a estrutura de controle de um programa do design processual clássico.

Antigamente, um exemplo importante disso era deixar uma estrutura manipular a comunicação entre uma interface do usuário e seu código, em vez de deixar seu código para gerar a interface do usuário diretamente.

Em tempos mais recentes (quando essas estruturas praticamente dominavam, então a questão não era mais relevante), um exemplo estava invertendo o controle sobre a instanciação de objetos.

Fowler e outros decidiram que o termo Inversão de controle cobria muitas técnicas e precisávamos de um novo termo para o exemplo específico de instanciação de objetos (injeção de dependência), mas, no momento em que esse acordo foi feito, a frase "IoC Container "decolou.

Isso atrapalha bastante a água, porque um contêiner de IoC é um tipo específico de Injeção de Dependência, mas a Injeção de Dependência é um tipo específico de Inversão de Controle. É por isso que você está recebendo respostas tão confusas, não importa para onde você olha.

pdr
fonte
4
Normalmente não voto muito, mas esta é uma ótima resposta. 1 voto não será suficiente. :(
RJD22
1
Esta resposta realmente responde a todas as questões de IoC e DI.
Ali Umair
32

Aqui estão os programas de fluxo de controle "regulares" geralmente seguidos:

  • Executar comandos sequencialmente
  • Você mantém controle sobre o fluxo de controle do programa

Inversão de controle "inverte" esse controle de fluxo, o que significa que ele vira de cabeça para baixo:

  • Seu programa não controla mais o fluxo. Em vez de chamar comandos como achar melhor, você espera que outra pessoa ligue para você .

Essa última linha é a mais importante. Em vez de ligar para outra pessoa quando lhe apetecer, alguém a chama quando lhe apetecer.

Um exemplo comum disso são estruturas da web como o Rails. Você define Controladores, mas na verdade não decide quando esses serão chamados. O Rails os chama quando decide que há uma necessidade.

dsw88
fonte
19
[insira obrigatória "em Soviética" piada aqui]
Robert Harvey
2
Brincadeiras à parte, o que eu acho que você está descrevendo é mais como a passagem de mensagens, que tem sido um item básico do OO há décadas.
22713 Robert Harvey
3
@ JimmyHoffa - Isso não está errado - veja aqui . Inversão de controle é um conceito mais geral do que criar dependências, e a injeção de dependência é apenas uma forma de IoC.
21413 Lee
7
@ JimmyHoffa: Eu discordo. Essa é uma definição correta de Inversão de controle tanto quanto a sua resposta ou a de Robert, que é exatamente a confusão que Fowler descreve ao cunhar a frase Injeção de dependência (que é o que vocês estão chamando de IoC).
pdr
5
Concordo com esta afirmação do @pdr: "Inversão de controle significa qualquer coisa que inverta a estrutura de controle de um programa do design de procedimentos clássico". É o que estou descrevendo e é a inversão genérica de controle. Injeção de dependência é um tipo de IoC, mas não é a única coisa que pratica IoC
dsw88
13

É sobre quem controla a instanciação de dependências.

Tradicionalmente, quando uma classe / método precisa usar outra classe (dependência), ela é instanciada diretamente pela classe / método. Ele controla suas dependências.

Com Inversion of Control (IoC), o chamador passou na dependência e, portanto, instancia a dependência. O chamador controla as dependências.

O controle de onde uma dependência é instanciada foi invertido - em vez de estar no "fundo", onde está o código que precisa, ele é instanciado no "topo", onde o código que precisa dela está sendo chamado.

Oded
fonte
1
Inglês não claro. Falhou.
22713 Robert Harvey
2
@RobertHarvey - quão simples é simples?
Oded
4
@RobertHarvey Huh? Isso parece bastante claro para mim ... O que não é claro? A palavra "instanciação" ou "dependências"?
21713 Jimmy Hoffa
@ JimmyHoffa: Veja minha resposta, que fornece um exemplo específico. IoC é um daqueles termos problemáticos que todo mundo usa, mas ninguém explica; as pessoas usam contêineres de IoC em programas que não precisam deles porque não compreendem. Dito isto, acho que essa resposta teve algumas edições ninjas. :)
Robert Harvey
Este e o post be @ dsw88 acima são bastante claros para mim. Olha, se eu nunca tivesse ouvido falar em IoC, pensaria intuitivamente: "Oh, onde quem controla algo muda de um lado para o outro"? Bom trabalho nisso!
Oliver Williams
2

Normalmente, o código de nível superior chama (ou seja, controla) o código de nível inferior. Main () chama function (), function () chama libraryFunction ().

Isso pode ser invertido, para que a função de biblioteca de baixo nível na parte inferior chame funções de nível superior.

Por que você faria isso? Middleware. Às vezes, você deseja controlar o nível superior e o inferior, mas há muito trabalho no meio que você simplesmente não quer fazer. Veja a implementação do quicksort no C stdlib . Você chama quicksort no nível superior. Você entrega a qsort () um ponteiro de função para sua própria função que implementa um comparador no que você quiser. Quando qsort () é chamado, chama essa função comparadora. qsort () está controlando / chamando / dirigindo sua função de alto nível.

Philip
fonte
1

Aqui está uma visão geral simples:

  1. Controle refere-se ao que o programa faz a seguir
  2. No nível superior, normalmente existem duas coisas que controlam o controle: o próprio aplicativo e o usuário

Antigamente, o controle era de propriedade do aplicativo primeiro e do usuário segundo. Se o aplicativo precisasse de algo do usuário, ele parava e perguntava e depois passava para a próxima tarefa. A interação do usuário forneceu principalmente dados, em vez de controlar o que o aplicativo fez a seguir. Isso é um pouco estranho para nós hoje em dia, já que não vemos esse tipo de comportamento com muita frequência.

Se mudarmos isso e oferecermos ao usuário o controle primário, invertemos o controle. Isso significa que, em vez de o usuário esperar o aplicativo dar algo para fazer, o aplicativo fica esperando o usuário dar algo para fazer. As GUIs são um ótimo exemplo disso e praticamente qualquer coisa com um loop de eventos inverteu o controle.

Observe que meu exemplo está no nível superior e que esse conceito de inversão de controle pode ser abstraído para diferentes camadas de controle dentro do aplicativo (ou seja, injeção de dependência). Pode ser por isso que é tão difícil obter uma resposta direta.

Loren
fonte
0

Vamos tentar entender isso através dos dois exemplos.

Exemplo 1

Nos dias anteriores, os aplicativos costumavam gerar prompts de comando para aceitar entradas do usuário, uma após a outra. Hoje, as estruturas de interface do usuário instanciam vários elementos da interface do usuário, percorrem vários eventos desses elementos da interface do usuário (como passar o mouse, clique etc.) e os programas usuário / principal fornecem ganchos (por exemplo, ouvintes de eventos da interface do usuário em Java) para ouvir esses eventos. Portanto, o fluxo principal "controle" do elemento da interface do usuário é movido do programa do usuário para a estrutura da interface do usuário. Nos dias anteriores, estava no programa do usuário.

Exemplo 2

Considere a classe CustomerProcessorabaixo:

class CustomerProcessor
{
    SqlCustRepo custRepo = new SqlCustRepo(); 
    private void processCustomers()
    {
            Customers[] custs = custRepo.getAllCusts();
    }
}

Se eu quiser processCustomer()ser independente de qualquer implementação getAllCusts(), e não apenas a fornecida por SqlCustRepo, precisarei me livrar da linha: SqlCustRepo custRepo = new SqlCustRepo()e substituí-la por algo mais genérico, capaz de aceitar vários tipos de implementação, de modo que processCustomers()simplesmente funcione para qualquer implementação fornecida. O código acima (instanciar a classe requerida SqlCustRepopela lógica do programa principal) é uma maneira tradicional e não atinge esse objetivo de se separar processCustomers()da implementação de getAllCusts(). Na inversão de controle, o contêiner instancia a classe de implementação necessária (conforme especificado por, digamos, configuração xml), injeta-a na lógica principal do programa que é vinculada conforme os ganchos especificados (digamos, por @Autowiredanotação ou getBean()método na estrutura de primavera).

Vamos ver como isso pode ser feito. Considere o código abaixo.

Config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <bean id="custRepo" class="JsonCustRepo" />
</beans>

CustRepo.java

interface ICustRepo 
{ ... }

JsonCustRepo.java

class JsonCustRepo implements CustRepo
{ ... }

App.java

class App
{
    public static void main(String[] args) 
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("Config.xml");
        ICustRepo custRepo = (JsonCustRepo) context.getBean("custRepo");
    }
}

Nós também podemos ter

class GraphCustRepo implements ICustRepo { ... }   

e

<bean id="custRepo" class="GraphCustRepo">

e não precisaremos alterar o App.java.

Acima do contêiner (que é a estrutura da primavera) tem a responsabilidade de verificar o arquivo xml, instanciar o bean de tipo específico e injetá-lo no programa do usuário. O programa do usuário não tem controle sobre qual classe é instanciada.

PS: IoC é um conceito genérico e é alcançado de várias maneiras. Os exemplos acima o alcançam por injeção de dependência.

Referência: artigo de Martin Fowler .

Mahesha999
fonte