¿Por qué se llama así la Inversión de control?

98

Las palabras inverto controlno se utilizan en absoluto para definir la Inversión de Control en las definiciones que he visto.

Definiciones

Wikipedia

La inversión de control (IoC) es una técnica de programación, expresada aquí en términos de programación orientada a objetos, en la que el acoplamiento de objetos está limitado en tiempo de ejecución por un objeto ensamblador y normalmente no se conoce en tiempo de compilación mediante análisis estático. ~ http://en.wikipedia.org/wiki/Inversion_of_control

Martin Fowler

La inversión de control es un patrón común en la comunidad Java que ayuda a conectar contenedores livianos o ensamblar componentes de diferentes proyectos en una aplicación cohesiva. ~ basado en http://www.martinfowler.com/articles/injection.html (redactado nuevamente)


Entonces, ¿por qué la Inversión de control se llama Inversión de control? ¿Qué control se invierte y por qué? ¿Hay alguna manera de definir la Inversión de Control usando la terminología: invertir y controlar ?

Korey Hinton
fuente
22
Accesorios para la persona que puede explicar esto en inglés simple.
Robert Harvey
2
Si una definición usara la palabra que estaba definiendo, eso sería una falla de un diccionario. Una lógica similar se aplica aquí.
Izkata
2
Ver también en StackOverflow: ¿Qué es la inversión de control?
Izkata
2
@Izkata, es muy común que los diccionarios definan frases en términos de sus propios términos o términos sinónimos. es decir: la definición de fuerza de la naturaleza usa las palabras fuerza y ​​naturaleza en su definición o la definición de términos de servicio usa las palabras reglas y servicio donde las reglas son sinónimos de términos.
Korey Hinton
3
Prefiero utilizar el término "inyección de dependencia automatizada" o ADI en lugar de IoC, por esta misma razón; El propio Fowler menciona que la mayoría de los paradigmas actuales en programación tienen algún tipo de "inversión de control", donde ese término se define generalmente como "la renuncia a las determinaciones del código a ejecutar y el momento en que debe ejecutarse a un externo sistema de control, cuando tales determinaciones son hechas tradicionalmente por el propio programa ". Todo, desde las interrupciones de hardware hasta la programación basada en eventos y las máquinas virtuales y la multitarea, sucede con IoC.
KeithS

Respuestas:

67

Digamos que tiene algún tipo de clase de "repositorio", y ese repositorio es responsable de entregarle los datos de una fuente de datos.

El repositorio podría establecer una conexión con la fuente de datos por sí mismo. Pero, ¿y si le permitiera pasar una conexión a la fuente de datos a través del constructor del repositorio?

Al permitir que la persona que llama proporcione la conexión, ha desacoplado la dependencia de conexión de la fuente de datos de la clase de repositorio, permitiendo que cualquier fuente de datos trabaje con el repositorio, no solo la especificada por el repositorio.

Ha invertido el control al transferir la responsabilidad de crear la conexión desde la clase de repositorio a la persona que llama.

Martin Fowler sugiere utilizar el término "Inyección de dependencias" para describir este tipo de Inversión de control, ya que la Inversión de control como concepto puede aplicarse de manera más amplia que simplemente inyectar dependencias en un método de constructor.

Robert Harvey
fuente
3
Este es un ejemplo de inyección de dependencia, pero la inyección de dependencia es solo un subconjunto de inversión de control. Hay otras cosas totalmente ajenas a la inyección de dependencia que practican la inversión del control.
dsw88
1
@ mustang2009cobra: Gracias. Un ejemplo es lo que estaba buscando, no un catálogo completo de instancias donde ocurre, y el término "Inversión de control" está más estrechamente asociado con DI, no con la transmisión de mensajes u otros conceptos similares.
Robert Harvey
Es cierto que la inyección de dependencia es el ejemplo más frecuente de IoC, por lo que un ejemplo de DI tiene más sentido. ¿Quizás un pequeño cambio en su respuesta que especifique que este es un ejemplo de DI, que es el tipo más prominente de IoC?
dsw88
1
¡Esto es exactamente lo que estaba buscando! Muchos ejemplos y definiciones de IoC no especifican claramente qué control se está invirtiendo. Me doy cuenta de que puede haber más en IoC que solo la inyección de dependencia, pero ahora algo finalmente hizo clic en mi cerebro. ¡Gracias!
Korey Hinton
79

No creo que nadie pueda explicarlo mejor que Martin Fowler, más abajo en el artículo al que se vinculó .

Para esta nueva generación de contenedores, la inversión se trata de cómo buscan una implementación de complemento. En mi ingenuo ejemplo, la lista buscó la implementación del buscador al instanciarla directamente. Esto evita que el buscador sea un complemento. El enfoque que utilizan estos contenedores es garantizar que cualquier usuario de un complemento siga alguna convención que permita que un módulo ensamblador separado inyecte la implementación en la lista.

Como explica en los párrafos anteriores, esto no es exactamente lo mismo que la razón por la cual se originó el término "Inversión de control".

Cuando estos contenedores hablan de cómo son tan útiles porque implementan "Inversión de control", termino muy perplejo. La inversión del control es una característica común de los marcos, por lo que decir que estos contenedores livianos son especiales porque usan inversión de control es como decir que mi automóvil es especial porque tiene ruedas.

La pregunta, ¿qué aspecto del control están invirtiendo? Cuando me topé con la inversión de control, estaba en el control principal de una interfaz de usuario. Las primeras interfaces de usuario fueron controladas por el programa de aplicación. Tendría una secuencia de comandos como "Ingresar nombre", "ingresar dirección"; su programa conduciría las indicaciones y respondería a cada una. Con las IU gráficas (o incluso basadas en la pantalla), el marco de la IU contendría este bucle principal y, en su lugar, su programa proporcionaría controladores de eventos para los diversos campos en la pantalla. El control principal del programa se invirtió, se alejó de usted al marco.

Es por eso que continúa acuñando el término "Inyección de dependencia" para cubrir esta implementación específica de Inversión de control.

Como resultado, creo que necesitamos un nombre más específico para este patrón. Inversión de control es un término demasiado genérico y, por lo tanto, las personas lo encuentran confuso. Como resultado de mucha discusión con varios defensores de la IoC, decidimos el nombre Inyección de dependencia.

Para aclarar un poco: Inversión de control significa cualquier cosa que invierta la estructura de control de un programa desde el diseño de procedimiento clásico.

En días anteriores, un ejemplo clave de esto era dejar que un marco manejara la comunicación entre una IU y su código, en lugar de dejar su código para generar la IU directamente.

En tiempos más recientes (cuando tales marcos dominaban bastante, por lo que la pregunta ya no era relevante), un ejemplo fue invertir el control sobre la creación de instancias de objetos.

Fowler y otros decidieron que el término Inversión de control abarcaba demasiadas técnicas y que necesitábamos un nuevo término para el ejemplo específico de creación de instancias de objetos (Inyección de dependencia) pero, para cuando se llegó a un acuerdo, la frase "Contenedor IoC "había despegado.

Esto enturbia mucho el agua, porque un contenedor de IoC es un tipo específico de inyección de dependencia, pero la inyección de dependencia es un tipo específico de inversión de control. Es por eso que obtienes respuestas tan confusas, sin importar dónde mires.

pdr
fuente
44
Normalmente no voto mucho, pero esta es una gran respuesta. 1 voto no será suficiente. :(
RJD22
1
Esta respuesta realmente responde a todas las preguntas sobre las confusiones de IoC y DI.
Ali Umair
32

Aquí están los programas de flujo de control "regulares" que generalmente se siguen:

  • Ejecuta comandos secuencialmente
  • Mantiene el control sobre el flujo de control del programa.

La inversión de Control "invierte" ese flujo de control, lo que significa que lo invierte:

  • Su programa ya no controla el flujo. En lugar de llamar a los comandos como mejor le parezca, espera a que alguien más lo llame .

Esa última línea es la importante. En lugar de llamar a alguien más cuando lo desee, alguien más lo llamará cuando lo desee.

Un ejemplo común de esto son los marcos web como Rails. Usted define Controladores, pero en realidad no decide cuándo se llaman. Rails los llama cuando decide que hay una necesidad.

dsw88
fuente
19
[inserte aquí una broma obligatoria "en soviético]
Robert Harvey
2
Bromas aparte, lo que creo que estás describiendo es más como pasar mensajes, que ha sido un elemento básico de OO durante décadas.
Robert Harvey
3
@JimmyHoffa - Esto no está mal en absoluto - mira aquí . La inversión del control es un concepto más general que la creación de dependencias, y la inyección de dependencias es solo una forma de IoC.
Lee
77
@ Jimmy Jimmy: No estoy de acuerdo. Esta es una definición tan correcta de Inversión de control como su respuesta o la de Robert, que es exactamente la confusión que Fowler describe al acuñar la frase Inyección de dependencia (que es lo que ambos llaman IoC).
pdr
55
Estoy de acuerdo con esta declaración de @pdr: "Inversión de control significa cualquier cosa que invierta la estructura de control de un programa desde el diseño clásico de procedimiento". Eso es lo que estoy describiendo, y esa es una inversión genérica de control. La inyección de dependencia es un tipo de IoC, pero no es lo único que practica IoC
dsw88
13

Se trata de quién controla la creación de instancias de dependencias.

Tradicionalmente, cuando una clase / método necesita usar otra clase (dependencia), la clase / método lo instancia directamente. Controla sus dependencias.

Con Inversion of Control (IoC), la persona que llama pasó la dependencia, por lo tanto, crea una instancia de la dependencia. La persona que llama controla las dependencias.

El control de dónde se instancia una dependencia se ha invertido; en lugar de estar en la "parte inferior", donde está el código que lo necesita, se instancia en la "parte superior", donde se llama al código que lo necesita.

Oded
fuente
1
No es simple inglés. Fallar.
Robert Harvey
2
@RobertHarvey: ¿qué tan simple es simple?
Oded
44
@RobertHarvey ¿Eh? Esto me parece bastante claro ... ¿Qué no es claro? La palabra "instanciación" o "dependencias"?
Jimmy Hoffa
@JimmyHoffa: Vea mi respuesta, que proporciona un ejemplo específico. IoC es uno de esos términos problemáticos que todos usan pero nadie explica; las personas usan contenedores IoC en programas que no los requieren porque no los entienden. Dicho esto, creo que esta respuesta tuvo un par de ediciones ninja. :)
Robert Harvey
Esto y la publicación be @ dsw88 anterior son bastante claros para mí. Mire, si nunca hubiera oído hablar de IoC, intuitivamente pensaría "Oh, dónde quién controla algo cambia de un lado a otro". Buen trabajo en esto!
Oliver Williams
2

Por lo general, las llamadas de código de nivel superior (es decir, los controles) son de código de nivel inferior. Main () llama a function (), function () llama a libraryFunction ().

Eso se puede invertir, por lo que la función de biblioteca de bajo nivel en la parte inferior llama a funciones de nivel superior.

¿Por qué harías eso? Middleware A veces quieres controlar el nivel superior y el nivel inferior, pero hay mucho trabajo en el medio que simplemente no quieres hacer. Tome la implementación de quicksort en C stdlib . Llamas a quicksort en el nivel superior. Usted le da a qsort () un puntero de función a su propia función que implementa un comparador en lo que desee. Cuando se llama qsort (), llama a esta función de comparación. qsort () está controlando / llamando / manejando su función de alto nivel.

Philip
fuente
1

Aquí hay una descripción general simple:

  1. El control se refiere a lo que el programa hace a continuación
  2. En el nivel superior, generalmente hay dos cosas que controlan el control: la aplicación misma y el usuario

En los viejos tiempos, el control era propiedad de la aplicación primero y el usuario segundo. Si la aplicación necesitaba algo del usuario, se detendría y preguntaría y luego pasaría a su siguiente tarea. La interacción del usuario proporcionó principalmente datos en lugar de controlar lo que la aplicación hizo a continuación. Esto es un poco extraño para nosotros hoy en día, ya que no vemos este tipo de comportamiento muy a menudo.

Si cambiamos eso y le damos al usuario el control primario, entonces hemos invertido el control. Esto significa que, en lugar de que el usuario espere a que la aplicación le dé algo que hacer, la aplicación se queda esperando a que el usuario le dé algo que hacer. Las GUI son un gran ejemplo de esto y casi todo lo que tenga un bucle de eventos ha invertido el control.

Tenga en cuenta que mi ejemplo está en el nivel superior y que este concepto de inversión de control puede abstraerse a diferentes capas de control dentro de la aplicación (es decir, inyección de dependencia). Esta puede ser la razón por la cual es tan difícil obtener una respuesta directa.

Loren
fuente
0

Tratemos de entenderlo a través de los dos ejemplos.

Ejemplo 1

En días anteriores, las aplicaciones solían generar indicaciones de comando para aceptar entradas de usuario una tras otra. Hoy en día, los marcos de la interfaz de usuario crean instancias de varios elementos de la interfaz de usuario, recorren varios eventos de esos elementos de la interfaz de usuario (como pasar el mouse, hacer clic, etc.) y los programas de usuario / principal proporcionan ganchos (por ejemplo, oyentes de eventos de la interfaz de usuario en Java) para escuchar esos eventos. Por lo tanto, el "control" del flujo de elementos de la interfaz de usuario principal se mueve del programa de usuario al marco de la interfaz de usuario. En días anteriores, estaba en el programa de usuario.

Ejemplo 2

Considere la clase a CustomerProcessorcontinuación:

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

Si quiero processCustomer()ser independiente de cualquier implementación getAllCusts(), no solo de la proporcionada por SqlCustRepo, tendré que deshacerme de la línea: SqlCustRepo custRepo = new SqlCustRepo()y reemplazarla con algo más genérico, capaz de aceptar un tipo variado de implementación, de modo que processCustomers()simplemente funcione para cualquier implementación provista. El código anterior (instanciando la clase requerida SqlCustRepopor la lógica del programa principal) es una forma tradicional y no logra este objetivo de desacoplarse processCustomers()de la implementación de getAllCusts(). En la inversión de control, el contenedor crea una instancia de la clase de implementación requerida (como se especifica por, digamos, la configuración xml), la inyecta en la lógica principal del programa que se enlaza según los ganchos especificados (por ejemplo, por @Autowiredanotación o getBean()método en Spring Framework).

Veamos cómo se puede hacer esto. Considere el siguiente código.

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

También podemos tener

class GraphCustRepo implements ICustRepo { ... }   

y

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

y no necesitaremos cambiar App.java.

Por encima del contenedor (que es el marco de Spring) tiene la responsabilidad de escanear el archivo xml, instanciar el bean de tipo específico e inyectarlo en el programa del usuario. El programa de usuario no tiene control sobre qué clase se instancia.

PD: IoC es un concepto genérico y se logra de muchas maneras. Los ejemplos anteriores lo logran mediante inyección de dependencia.

Referencia: artículo de Martin Fowler .

Mahesha999
fuente