Por que a Inversão de Controle é nomeada dessa maneira?

93

As palavras invert ou control não são usadas para definir Inversão de Controle nas definições que vi.

Definições

Wikipedia

inversion of control (IoC) is a programming technique, expressed here in terms of object-oriented programming, in which object coupling is bound at run time by an assembler object and is typically not known at compile time using static analysis. ~http://en.wikipedia.org/wiki/Inversion_of_control

Martin Fowler

Inversion of Control is a common pattern in the Java community that helps wire lightweight containers or assemble components from different projects into a cohesive application. ~ based on http://www.martinfowler.com/articles/injection.html (reworded)

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

    
por Korey Hinton 22.07.2013 / 18:36
fonte

7 respostas

65

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

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

Ao permitir que o chamador forneça a conexão, você desvinculou a dependência da conexão da fonte de dados da classe de repositório, permitindo que qualquer fonte de dados trabalhe com o repositório, não apenas aquele que o repositório especifica .

Você tem controle invertido ao entregar a responsabilidade de criar a conexão da classe de repositório para o chamador.

Martin Fowler sugere o uso do termo "Injeção de Dependência" para descrever este tipo de Inversão de Controle, já que a Inversão do Controle como um conceito pode ser aplicada mais amplamente do que apenas injetar dependências em um método construtor.

    
por 22.07.2013 / 18:50
fonte
76

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

For this new breed of containers the inversion is about how they lookup a plugin implementation. In my naive example the lister looked up the finder implementation by directly instantiating it. This stops the finder from being a plugin. The approach that these containers use is to ensure that any user of a plugin follows some convention that allows a separate assembler module to inject the implementation into the lister.

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.

When these containers talk about how they are so useful because they implement "Inversion of Control" I end up very puzzled. Inversion of control is a common characteristic of frameworks, so saying that these lightweight containers are special because they use inversion of control is like saying my car is special because it has wheels.

The question, is what aspect of control are they inverting? When I first ran into inversion of control, it was in the main control of a user interface. Early user interfaces were controlled by the application program. You would have a sequence of commands like "Enter name", "enter address"; your program would drive the prompts and pick up a response to each one. With graphical (or even screen based) UIs the UI framework would contain this main loop and your program instead provided event handlers for the various fields on the screen. The main control of the program was inverted, moved away from you to the framework.

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

As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.

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

Nos dias anteriores, um exemplo importante disso era permitir que uma estrutura manipulasse 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 esses frameworks praticamente dominavam, então a questão não era mais relevante), um exemplo era inverter o controle sobre a instanciação de objetos.

Fowler, e outros, decidiram que o termo Inversão de Controle cobria muitas técnicas e nós 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 o acordo foi feito, a frase "IoC Container" havia decolado.

Isso confunde muito a água, porque um contêiner 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 onde você olhe.

    
por 22.07.2013 / 18:50
fonte
30

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

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

Inversão de Controle "inverte" esse fluxo de controle, o que significa que ele gira sobre sua cabeça:

  • Seu programa não controla mais o fluxo. Em vez de chamar comandos como achar melhor, você espera que alguém os chame .

Essa última linha é a mais importante. Ao invés de chamar alguém quando você quiser, alguém o chama quando sentir vontade.

Um exemplo comum disso são os frameworks web, como o Rails. Você define Controllers, mas na verdade não decide quando eles são chamados. Rails os chama quando decide que é necessário.

    
por 22.07.2013 / 19:33
fonte
12

É 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. Controla suas dependências.

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

O controle de onde uma dependência é instanciada foi invertido - ao invés de estar no "bottom", onde o código que precisa é, é instanciado no "top", onde o código que precisa dele está sendo chamado .

    
por 22.07.2013 / 18:40
fonte
2

Normalmente, chamadas de código de nível mais alto (isto é, controles) código de nível inferior. Main () chama function (), function () chama libraryFunction ().

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

Por que você faria isso? Middleware. Às vezes você quer controlar o nível superior e o inferior, mas há muito trabalho no meio que você não quer fazer. Tome a implementação do quicksort no diretório padrão . Você chama quicksort no nível superior. Você entrega qsort () um ponteiro de função para sua própria função que implementa um comparador em qualquer coisa que você queira. Quando qsort () é chamado, ele chama essa função de comparação. qsort () está controlando / chamando / dirigindo sua função de alto nível.

    
por 22.07.2013 / 20:23
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 há duas coisas que controlam o controle: o aplicativo em si e o usuário

Antigamente, o controle era de propriedade do aplicativo primeiro e do segundo usuário. Se o aplicativo precisasse de algo do usuário, ele pararia e perguntaria e então passaria para a próxima tarefa. A interação do usuário forneceu principalmente dados em vez de controlar o que o aplicativo fez em seguida. 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 fornecermos ao usuário o controle primário, invertemos o controle. Isso significa que, em vez de o usuário aguardar o aplicativo para dar algo a fazer, o aplicativo fica esperando que o usuário dê a ele algo para fazer. As GUIs são um ótimo exemplo disso e praticamente qualquer coisa com um loop de eventos tem controle invertido.

Observe que meu exemplo está no nível mais alto 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). Talvez seja por isso que é tão difícil obter uma resposta direta.

    
por 11.05.2015 / 17:26
fonte
0

Vamos tentar entendê-lo através dos dois exemplos.

Exemplo 1

Nos primeiros dias, os aplicativos eram usados para gerar prompts de comando para aceitar as entradas do usuário uma após a outra. Hoje, as estruturas de UI 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 o usuário / programas principais fornece ganchos (por exemplo, ouvintes de eventos da UI em Java) para escutar esses eventos. Assim, o fluxo de elemento da interface do usuário principal "control" é 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 CustomerProcessor abaixo:

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

Se eu quiser que processCustomer() seja independente de qualquer implementação de getAllCusts() , não apenas da fornecida por SqlCustRepo , precisarei me livrar da linha: SqlCustRepo custRepo = new SqlCustRepo() e substituí-la por algo mais genérico, capaz de aceitar um tipo variado de implementação, de forma que o processCustomers() simplesmente funcione para qualquer implementação fornecida. O código acima (instanciando a classe requerida SqlCustRepo pela lógica do programa principal) é uma maneira tradicional e não atinge essa meta de desacoplar processCustomers() da implementação de getAllCusts() . Na inversão de controle, o contêiner instancia a classe de implementação requerida (como especificado por, digamos, configuração xml), injeta na lógica principal do programa que fica vinculada conforme os ganchos especificados (digamos por @Autowired annotation ou getBean() method na mola framework).

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");
    }
}

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 é o framework Spring) tem a responsabilidade de escanear o arquivo xml, instanciar o bean de um 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. Exemplos acima alcançados por injeção de dependência.

Referência: artigo de Martin Fowler .

    
por 03.08.2018 / 11:50
fonte