¿Qué es la inversión de control?


1826

La inversión de control (IoC) puede ser bastante confusa cuando se encuentra por primera vez.

  1. ¿Qué es?
  2. ¿Qué problema resuelve?
  3. ¿Cuándo es apropiado usar y cuándo no?

292
El problema con la mayoría de estas respuestas es la terminología utilizada. ¿Qué es un contenedor? ¿Inversión? ¿Dependencia? Explícalo en términos simples sin las grandes palabras.
kirk.burleson

13
Ver también en Programadores. SE: ¿Por qué se llama así a la Inversión de control?
Izkata

8
Es Inyección de Dependencia (DI) - vea la descripción de Martin Fowlers aquí: martinfowler.com/articles/injection.html#InversionOfControl
Ricardo Sanchez


Es un adjetivo, no un sustantivo, no es una cosa, es una descripción de un cambio realizado en el código, donde el control del flujo está en el delegado, no en el contenedor.
Martin Spamer

Respuestas:


1523

Los patrones de Inversión de control (IoC) e Inyección de dependencias (DI) tienen que ver con eliminar las dependencias de su código.

Por ejemplo, supongamos que su aplicación tiene un componente de editor de texto y desea proporcionar la corrección ortográfica. Su código estándar se vería así:

public class TextEditor {

    private SpellChecker checker;

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

Lo que hemos hecho aquí crea una dependencia entre el TextEditory el SpellChecker. En un escenario de IoC, haríamos algo como esto:

public class TextEditor {

    private IocSpellChecker checker;

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

En el primer ejemplo de código estamos instanciando SpellChecker( this.checker = new SpellChecker();), lo que significa que la TextEditorclase depende directamente de la SpellCheckerclase.

En el segundo ejemplo de código, estamos creando una abstracción al tener la SpellCheckerclase de dependencia en TextEditorla firma del constructor (no inicializando la dependencia en la clase). Esto nos permite llamar a la dependencia y luego pasarla a la clase TextEditor así:

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

Ahora el cliente que crea la TextEditorclase tiene control sobre qué SpellCheckerimplementación usar porque estamos inyectando la dependencia en la TextEditorfirma.


50
Buen ejemplo claro. Sin embargo, supongamos que en lugar de exigir que la interfaz ISpellChecker se pase al constructor del objeto, la exponemos como una propiedad configurable (o método SetSpellChecker). ¿Esto todavía constituiría IoC?
devios1

25
chainguy1337 - sí lo haría. El uso de setters como ese se denomina inyección de setter en oposición a la inyección de constructor (ambas técnicas de inyección de dependencia). IoC es un patrón bastante genérico, pero la inyección de dependencia logra IoC
Jack Ukleja

257
A pesar de los muchos votos positivos, esta respuesta es incorrecta. Consulte martinfowler.com/articles/injection.html#InversionOfControl . En particular, tenga en cuenta la parte que dice "Inversión de control es un término demasiado genérico, y por lo tanto la gente lo encuentra confuso. Como resultado de mucha discusión con varios defensores de IoC, decidimos el nombre Inyección de dependencia".
Rogério

45
Estoy de acuerdo con @Rogeria. esto no explica por qué se llama IoC y me sorprende la cantidad de votos ;-)
Aravind Yarram

31
Estoy del lado de @Rogerio y @Pangea. Este puede ser un buen ejemplo para la inyección del constructor, pero no una buena respuesta a la pregunta original. IoC, tal como lo define Fowler , puede realizarse sin utilizar ningún tipo de inyección, por ejemplo, utilizando un localizador de servicios o incluso una simple herencia.
mtsz

642

La inversión de control es lo que obtienes cuando las devoluciones de llamada de tu programa, por ejemplo, como un programa gui.

Por ejemplo, en un menú de la vieja escuela, podría tener:

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

controlando así el flujo de interacción del usuario.

En un programa GUI o somesuch, en su lugar decimos:

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

Así que ahora el control está invertido ... en lugar de que la computadora acepte la entrada del usuario en un orden fijo, el usuario controla el orden en que se ingresan los datos y cuando los datos se guardan en la base de datos.

Básicamente, cualquier cosa con un bucle de eventos, devoluciones de llamada o disparadores de ejecución cae en esta categoría.


161
No marques a este tipo. técnicamente tiene razón martinfowler.com/bliki/InversionOfControl.html IoC es un director muy general. El flujo de control se "invierte" por inyección de dependencia porque ha delegado efectivamente dependencias a algún sistema externo (por ejemplo, contenedor IoC)
Jack Ukleja

38
De acuerdo con el comentario de Schneider. 5 votos a favor? La mente se aturde, ya que esta es la única respuesta que es realmente correcta. Tenga en cuenta la apertura: ' como un programa gui'. La inyección de dependencia es solo la realización más comúnmente vista de IoC.
Jeff Sternal

40
De hecho, esta es una de las pocas respuestas correctas . Chicos, IoC no se trata fundamentalmente de dependencias. De ningún modo.
Rogério

13
+1: esta es una buena descripción (con un ejemplo) de la siguiente declaración de Martin Fowler: "Las primeras interfaces de usuario estaban controladas por el programa de aplicación. Tendría una secuencia de comandos como" Ingrese el nombre "," ingrese la dirección "; su el programa conduciría las indicaciones y recogería una respuesta a cada una. Con interfaces gráficas (o incluso basadas en pantalla), el marco de la interfaz de usuario contendría este bucle principal y su programa proporcionaría controladores de eventos para los diversos campos en la pantalla. el programa se invirtió, se alejó de ti al marco ".
Ashish Gupta

14
Ahora entiendo por qué a veces se le llama graciosamente como el "Principio de Hollywood: no nos llames, te llamaremos"
Alexander Suraphel el

419

¿Qué es la inversión de control?

Si sigue estos dos simples pasos, ha realizado una inversión de control:

  1. Separar lo -to-separe de cuando -to-separe.
  2. Asegúrese de que cuando parte sepa lo menos posible sobre qué parte; y viceversa.

Existen varias técnicas posibles para cada uno de estos pasos en función de la tecnología / lenguaje que está utilizando para su implementación.

-

La parte de inversión de la Inversión de Control (IoC) es lo confuso; porque inversión es el término relativo. ¡La mejor manera de entender IoC es olvidarse de esa palabra!

-

Ejemplos

  • Manejo de eventos. Controladores de eventos (parte de qué hacer) - Generar eventos (parte de cuándo hacer)
  • Interfaces Cliente componente (parte de qué hacer): implementación de la interfaz de componente (parte de qué hacer)
  • x Unidad fija. Configuración y TearDown (parte de qué hacer): xUnit framework llama a la configuración al principio y TearDown al final (parte de cuándo hacer)
  • Patrón de diseño de método de plantilla. parte de cuándo hacer el método de plantilla: parte de qué hacer de implementación de subclase primitiva
  • Métodos de contenedor de DLL en COM. DllMain, DllCanUnload, etc. (parte de qué hacer) - COM / OS (parte de cuándo hacer)

Cómo se dice Interfaces. El cliente componente (parte de cuándo hacer) como "cuándo" no tiene sentido cuando usamos interfaces (Ej: Inyección de dependencias), simplemente lo resumimos y le damos al cliente flexibilidad para agregar cualquier implementación, pero no hay "cuándo" involucrado allí. Estoy de acuerdo con "cuándo" en caso de que se produzcan eventos de gestión de eventos.
OldSchool

Por "cliente componente" me refería al usuario / cliente de la interfaz. El cliente sabe "cuándo" activar la parte "qué hacer" si la intención es extender la funcionalidad o no.
rpattabi

Echa un vistazo a este maravilloso artículo de Martin Fowler. Muestra cómo las interfaces hacen la parte fundamental de la inversión de control: martinfowler.com/articles/injection.html#InversionOfControl
rpattabi

Las dos primeras oraciones son brillantes. increíble !! ¡Separación perfecta por cuándo hacer y qué hacer! No sé por qué otras respuestas obtienen tantos votos positivos. solo hablan códigos sin ningún entendimiento.
Amir Ziarati

2
Me gusta la explicación what-to-doywhen-to-do
KimchiMan

164

La inversión de los controles se trata de separar las preocupaciones.

Sin IoC : tienes una computadora portátil y accidentalmente rompes la pantalla. Y maldita sea, usted encuentra que la misma pantalla del portátil modelo no está en ninguna parte del mercado. Entonces estás atrapado.

Con IoC : tienes un escritorio computadora de y accidentalmente rompes la pantalla. Descubres que puedes tomar casi cualquier monitor de escritorio del mercado, y funciona bien con tu escritorio.

Su escritorio implementa exitosamente IoC en este caso. Acepta una variedad de monitores, mientras que la computadora portátil no, necesita una pantalla específica para arreglarse.


1
@Luo Jiong Hui Buena explicación.
Sachin

3
La mayoría de los patrones de diseño, si no todos, tienen sus contrapartes en nuestra vida diaria que vemos y entendemos tan bien. La forma más eficiente de entender un patrón de diseño es conocer a sus contrapartes de la vida diaria. Y creo que hay muchos.
Luo Jiong Hui

66
Respuesta incorrecta. Está explicando la inyección de dependencia y no IoC. Vea el comentario de Rogério sobre esta respuesta arriba
MickyD

2
Estoy de acuerdo. Esto es DI, no IoC. Todavía recibe un voto positivo, porque es un enfoque simple, pero ayuda a ampliar la comprensión del tema.
Marzo

Explica la inyección de dependencia. No Ioc Pero agradable y clara explicación.
Chamin Wickramarathna

120

Inversion of Control, (o IoC), se trata de obtener la libertad (te casas, pierdes la libertad y estás siendo controlado. Te divorciaste, acabas de implementar Inversion of Control. Eso es lo que llamamos "desacoplado". Buen sistema informático desalienta algunas relaciones muy cercanas.) más flexibilidad (la cocina en su oficina solo sirve agua limpia del grifo, esa es su única opción cuando quiere beber. Su jefe implementó la Inversión de control al configurar una nueva máquina de café. Ahora obtiene la flexibilidad para elegir agua del grifo o café) y menos dependencia (Su pareja tiene un trabajo, usted no tiene un trabajo, depende económicamente de su pareja, por lo que está controlado. Encuentra un trabajo, ha implementado la Inversión de control. Un buen sistema informático fomenta la dependencia).

Cuando usa una computadora de escritorio, ha esclavizado (o, por ejemplo, controlado). Tienes que sentarte ante una pantalla y mirarla. Usando el teclado para escribir y usando el mouse para navegar. Y un software mal escrito puede esclavizarte aún más. Si reemplaza su escritorio con una computadora portátil, entonces invirtió un poco el control. Puede tomarlo fácilmente y moverse. Así que ahora puedes controlar dónde estás con tu computadora, en lugar de que tu computadora lo controle.

Al implementar la Inversión de control, un consumidor de software / objeto obtiene más controles / opciones sobre el software / objetos, en lugar de ser controlado o tener menos opciones.

Con las ideas anteriores en mente. Todavía extrañamos una parte clave de IoC. En el escenario de IoC, el consumidor de software / objeto es un marco sofisticado. Eso significa que el código que creó no lo llama usted mismo. Ahora expliquemos por qué esta manera funciona mejor para una aplicación web.

Supongamos que su código es un grupo de trabajadores. Necesitan construir un auto. Estos trabajadores necesitan un lugar y herramientas (un marco de software) para construir el automóvil. Un marco de software tradicional será como un garaje con muchas herramientas. Por lo tanto, los trabajadores deben hacer un plan ellos mismos y usar las herramientas para construir el automóvil. Construir un automóvil no es un negocio fácil, será muy difícil para los trabajadores planificar y cooperar adecuadamente. Un modernoEl marco de software será como una fábrica de automóviles moderna con todas las instalaciones y gerentes en su lugar. Los trabajadores no tienen que hacer ningún plan, los gerentes (parte del marco, son las personas más inteligentes y elaboraron el plan más sofisticado) ayudarán a coordinar para que los trabajadores sepan cuándo hacer su trabajo (el marco llama a su código). Los trabajadores solo necesitan ser lo suficientemente flexibles como para usar cualquier herramienta que los gerentes les den (mediante el uso de la inyección de dependencia).

Aunque los trabajadores dan el control de la gestión del proyecto en el nivel superior a los gerentes (el marco). Pero es bueno contar con la ayuda de algunos profesionales. Este es realmente el concepto de IoC.

Las aplicaciones web modernas con una arquitectura MVC dependen del marco para realizar el enrutamiento de URL y poner los controladores en su lugar para que el marco llame.

La inyección de dependencia y la inversión de control están relacionadas. La inyección de dependencia está en el nivel micro y la inversión de control está en el nivel macro . Tienes que comer cada bocado (implementar DI) para terminar una comida (implementar IoC).


21
He votado a favor de comparar la DI con el matrimonio y la CD con el divorcio.
Marek Bar

"Aunque los trabajadores dan el control de la gestión del proyecto en el nivel superior a los gerentes (el marco). Pero es bueno contar con la ayuda de algunos profesionales. Este es el concepto de IoC de donde realmente provienen". - En primer lugar, el control es con el gerente ¿Puedes explicar cómo se invierte ese control? Con la ayuda de profesionales (¿qué tipo de profesional)? Cómo ?
Istiaque Ahmed

@Istiaque Ahmed, en comparación con un garaje donde los trabajadores tienen el control total de todo, los gerentes en la fábrica de automóviles modernos controlan la producción. Así que ahora los trabajadores están controlados en lugar de controlar. Tenga en cuenta que los gerentes en este contexto son parte de la fábrica de automóviles modernos, no parte de los trabajadores. Los profesionales son los gerentes profesionales en la planificación y fabricación de automóviles.
Luo Jiong Hui

2
Mensaje para las personas casadas: no se divorcie ahora, las clases de su hijo también pueden implementar IoC.
Julian

Sí, esto lo justo mi visión sobre el matrimonio también COI
Balron

94

Antes de usar Inversion of Control, debe ser consciente del hecho de que tiene sus pros y sus contras, y debe saber por qué lo usa si lo hace.

Pros:

  • Su código se desacopla para que pueda intercambiar fácilmente implementaciones de una interfaz con implementaciones alternativas
  • Es un fuerte motivador para codificar contra interfaces en lugar de implementaciones
  • Es muy fácil escribir pruebas unitarias para su código porque no depende de nada más que los objetos que acepta en su constructor / configurador y puede inicializarlos fácilmente con los objetos correctos de forma aislada.

Contras:

  • IoC no solo invierte el flujo de control en su programa, sino que también lo nubla considerablemente. Esto significa que ya no puede simplemente leer su código y saltar de un lugar a otro porque las conexiones que normalmente estarían en su código ya no están en el código. En cambio, es en archivos de configuración XML o anotaciones y en el código de su contenedor IoC que interpreta estos metadatos.
  • Surge una nueva clase de errores en los que obtiene su configuración XML o sus anotaciones incorrectas y puede pasar mucho tiempo descubriendo por qué su contenedor IoC inyecta una referencia nula en uno de sus objetos bajo ciertas condiciones.

Personalmente, veo los puntos fuertes de IoC y realmente me gustan, pero tiendo a evitar IoC siempre que sea posible porque convierte su software en una colección de clases que ya no constituyen un programa "real", sino simplemente algo que debe ser organizado por Configuración XML o metadatos de anotación y se desmoronarían (y se desmoronarían) sin él.


3
La primera estafa es incorrecta. Idealmente, solo debería haber 1 uso del contenedor IOC en su código, y ese es su método principal. Todo lo demás debería caer en cascada desde allí
mwjackson

23
Creo que lo que quiere decir es que no puede simplemente leer: myService.DoSomething () e ir a la definición de DoSomething, porque con IoC, myService es solo una interfaz, y la implementación real es desconocida para usted, a menos que vaya a buscar en archivos de configuración xml o el método principal donde se configura su ioc.
Chrismay

77
Ahí es donde Resharper ayuda: "haga clic en ir a implementación" en la interfaz. Evitar la COI (o más específicamente DI de su ejemplo) probablemente también significa que no se está probando adecuadamente
IThasTheAnswer

10
Re: convierte su software en una colección de clases que ya no constituyen un programa "real", sino algo que necesita ser ensamblado por la configuración XML o metadatos de anotación y se desmoronaría (y se desmoronaría) sin él . Creo que esto Es muy engañoso. Lo mismo podría decirse de cualquier programa escrito sobre un marco. La diferencia con un buen contenedor de IoC es que, si su programa está bien diseñado y escrito, debería poder sacarlo y colocarlo en otro con cambios mínimos en su código, o desechar IoC por completo y construir sus objetos a mano .
The Awnry Bear

77
¡Es bueno ver una respuesta del mundo real como esta! Creo que hay muchos programadores experimentados, cómodos con el diseño orientado a objetos y las prácticas TDD, que ya utilizan interfaces, patrones de fábrica, modelos controlados por eventos y burlas donde tiene sentido, antes de que se inventara esta palabra de moda "IoC". Desafortunadamente, muchos desarrolladores / "arquitectos" afirman que son malas prácticas si no usas sus marcos preferidos. Prefiero un mejor diseño, uso de conceptos y herramientas de lenguaje integrados, para lograr el mismo objetivo con una fracción de la complejidad, es decir, sin "nublar" la implementación como usted dice :-)
Tony Wall

68
  1. Artículo de Wikipedia . Para mí, la inversión de control es convertir su código escrito secuencialmente y convertirlo en una estructura de delegación. En lugar de que su programa controle explícitamente todo, su programa configura una clase o biblioteca con ciertas funciones a las que se llamará cuando sucedan ciertas cosas.

  2. Resuelve la duplicación de código. Por ejemplo, en los viejos tiempos escribiría manualmente su propio bucle de eventos, sondeando las bibliotecas del sistema en busca de nuevos eventos. Hoy en día, en las API más modernas, simplemente le dice a las bibliotecas del sistema en qué eventos está interesado, y le informará cuándo suceden.

  3. La inversión del control es una forma práctica de reducir la duplicación de código, y si te encuentras copiando un método completo y solo cambiando una pequeña parte del código, puedes considerar abordarlo con una inversión de control. La inversión del control se facilita en muchos idiomas mediante el concepto de delegados, interfaces o incluso punteros de función sin formato.

    No es apropiado usarlo en todos los casos, porque el flujo de un programa puede ser más difícil de seguir cuando se escribe de esta manera. Es una forma útil de diseñar métodos al escribir una biblioteca que se reutilizará, pero debe usarse con moderación en el núcleo de su propio programa a menos que realmente resuelva un problema de duplicación de código.


37
Encuentro ese artículo de Wikipedia muy confuso y necesito arreglarlo. Mira la página de discusión para reírte.
devios1

Escribir su propio bucle de eventos aún podría ser una inversión de control, si ese bucle de eventos toma el lugar de un marco y el resto del código está utilizando el principio de IoC, acaba de escribir su propio marco. En realidad, esto no es algo malo, aumenta la legibilidad al precio de solo un poco más de codificación (no es que sea siempre apropiado tampoco).
lijat

45

Pero creo que debes tener mucho cuidado con eso. Si usa en exceso este patrón, hará un diseño muy complicado y un código aún más complicado.

Como en este ejemplo con TextEditor: si solo tiene un SpellChecker, ¿tal vez no sea realmente necesario usar IoC? A menos que necesite escribir pruebas unitarias o algo así ...

De todos modos: sea razonable. Los patrones de diseño son buenas prácticas, pero no se debe predicar la Biblia. No lo pegues en todas partes.


3
¿Cómo sabes que solo tendrás un corrector ortográfico?
Rastrear el

@Trace Podría saber cómo se va a utilizar, por ejemplo, el programa que va a escribir. Aún así, algunas técnicas como la inyección de dependencia son tan baratas que rara vez hay una razón para no usarlas en un caso como este.
lijat

44

IoC / DI para mí está eliminando las dependencias de los objetos que llaman. Súper simple

La respuesta que no es técnica es poder cambiar el motor de un automóvil justo antes de encenderlo. Si todo se conecta correctamente (la interfaz), está bien.


44

Supongamos que eres un objeto. Y vas a un restaurante:

Sin IoC : pides "manzana", y siempre te sirven manzana cuando pides más.

Con IoC : puede pedir "fruta". Puedes obtener diferentes frutas cada vez que te sirven. por ejemplo, manzana, naranja o sandía.

Entonces, obviamente, IoC se prefiere cuando te gustan las variedades.


26
  1. La inversión del control es un patrón utilizado para desacoplar componentes y capas en el sistema. El patrón se implementa mediante la inyección de dependencias en un componente cuando se construye. Estas dependencias generalmente se proporcionan como interfaces para un mayor desacoplamiento y para soportar la capacidad de prueba. Los contenedores IoC / DI como Castle Windsor, Unity son herramientas (bibliotecas) que se pueden usar para proporcionar IoC. Estas herramientas proporcionan características extendidas más allá de la simple administración de dependencias, que incluyen la vida útil, AOP / Intercepción, políticas, etc.

  2. a. Alivia a un componente de ser responsable de administrar sus dependencias.
    si. Proporciona la capacidad de intercambiar implementaciones de dependencia en diferentes entornos.
    C. Permite probar un componente a través de la burla de las dependencias.
    re. Proporciona un mecanismo para compartir recursos en una aplicación.

  3. a. Crítico cuando se realiza un desarrollo basado en pruebas. Sin IoC puede ser difícil de probar, porque los componentes bajo prueba están altamente acoplados al resto del sistema.
    si. Crítico al desarrollar sistemas modulares. Un sistema modular es un sistema cuyos componentes se pueden reemplazar sin necesidad de recompilación.
    C. Es crítico si hay muchas preocupaciones transversales que deben abordarse, en particular en una aplicación empresarial.


2
En realidad, IoC no se trata principalmente de administrar dependencias. Consulte martinfowler.com/articles/injection.html#InversionOfControl. En particular, tenga en cuenta la parte que dice "Inversión de control es un término demasiado genérico y, por lo tanto, la gente lo encuentra confuso. Como resultado de mucha discusión con varios defensores de IoC, se decidió por el nombre Inyección de dependencia ".
Rogério

26

Respondiendo solo la primera parte. ¿Qué es?

Inversion of Control (IoC) significa crear instancias de dependencias primero y última instancia de una clase (opcionalmente inyectándolas a través del constructor), en lugar de crear primero una instancia de la clase y luego la instancia de clase creando instancias de dependencias. Por lo tanto, la inversión de control invierte el flujo de control del programa. En lugar de que la persona que llama controle el flujo de control (mientras crea dependencias), la persona que llama controla el flujo de control del programa .


No se trata de la creación de clases u objetos, consulte martinfowler.com/articles/injection.html#InversionOfControl
Raghvendra Singh el

22

Escribiré mi simple comprensión de estos dos términos:

For quick understanding just read examples*

Inyección de dependencia (DI): la
inyección de dependencia generalmente significa pasar un objeto del cual depende el método, como parámetro a un método, en lugar de hacer que el método cree el objeto dependiente .
Lo que significa en la práctica es que el método no depende directamente de una implementación particular; cualquier implementación que cumpla con los requisitos se puede pasar como un parámetro.

Con esto los objetos cuentan sus dependencias. Y la primavera lo hace disponible.
Esto conduce al desarrollo de aplicaciones poco acopladas.

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

Contenedor de Inversión de Control (IoC):
Esta es una característica común de los marcos, el COI gestiona objetos java
, desde la creación de instancias hasta la destrucción a través de su BeanFactory.
-Los componentes de Java que son instanciados por el contenedor de IoC se denominan beans, y el contenedor de IoC gestiona el alcance de un bean, los eventos del ciclo de vida y cualquier característica de AOP para la que se haya configurado y 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.

Al implementar Inversion of Control, un consumidor de software / objeto obtiene más controles / opciones sobre el software / objetos, en lugar de ser controlado o tener menos opciones.

La inversión del control como guía de diseño sirve para los siguientes propósitos:

Hay un desacoplamiento de la ejecución de una determinada tarea de la implementación.
Cada módulo puede centrarse en para qué está diseñado.
Los módulos no hacen suposiciones sobre lo que hacen otros sistemas, sino que dependen de sus contratos.
Reemplazar módulos no tiene ningún efecto secundario sobre otros módulos
. Aquí mantendré las cosas abstractas. Puede visitar los siguientes enlaces para obtener una comprensión detallada del tema.
Una buena lectura con ejemplo

Explicación detallada


17

Estoy de acuerdo con NilObject , pero me gustaría agregar a esto:

si te encuentras copiando un método completo y solo cambiando una pequeña parte del código, puedes considerar abordarlo con una inversión de control

Si te encuentras copiando y pegando código, casi siempre estás haciendo algo mal. Codificado como el principio de diseño Once and Only Once .


17

Por ejemplo, la tarea # 1 es crear un objeto. Sin el concepto IOC, la tarea n. ° 1 debe ser realizada por el Programador, pero con el concepto IOC, la tarea n. ° 1 se realizaría por contenedor.

En resumen, el control se invierte del programador al contenedor. Entonces, se llama inversión de control.

Encontré un buen ejemplo aquí .


Un contenedor es un concepto en IoC donde el modelo de objeto, incluidas las dependencias (relaciones entre el objeto "usuario" y el objeto "usado") y las instancias de objeto, residen y se administran, por ejemplo, están contenidas. El contenedor generalmente lo proporciona un marco de trabajo de IoC, como Spring. Piense en ello como un repositorio de tiempo de ejecución para los objetos que componen su aplicación.
The Awnry Bear

17

Digamos que hacemos alguna reunión en algún hotel.

Mucha gente, muchas garrafas de agua, muchos vasos de plástico.

Cuando alguien quiere beber, ella llena la taza, bebe y tira la taza al suelo.

Después de una hora o algo así, tenemos un piso cubierto de vasos de plástico y agua.

Deje invertir el control.

La misma reunión en el mismo lugar, pero en lugar de vasos de plástico tenemos un camarero con un vaso de vidrio (Singleton)

y ella siempre ofrece bebidas a los invitados.

Cuando alguien quiere beber, ella toma del vaso de camarero, bebe y se lo devuelve al camarero.

Dejando a un lado la cuestión de la higiene, la última forma de control del proceso de bebida es mucho más efectiva y económica.

Y esto es exactamente lo que hace Spring (otro contenedor de IoC, por ejemplo: Guice). En lugar de dejar que la aplicación cree lo que necesita usando una nueva palabra clave (tomar un vaso de plástico), el contenedor Spring IoC ofrece a la aplicación la misma instancia (singleton) del objeto necesario (vaso de agua).

Piense en usted como organizador de dicha reunión. Necesita la forma de enviar un mensaje a la administración del hotel que

los miembros de la reunión necesitarán un vaso de agua pero no un pedazo de pastel.

Ejemplo:-

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

}

Enlaces útiles:-


¿No son objetos de tipo estático singletons?
Gokigooooks

16

Parece que lo más confuso de "IoC", el acrónimo y el nombre que representa, es que es un nombre demasiado glamoroso, casi un nombre ruidoso.

¿Realmente necesitamos un nombre para describir la diferencia entre la programación basada en procedimientos y la de eventos? De acuerdo, si es necesario, pero ¿debemos elegir un nuevo nombre "más grande que la vida" que confunda más de lo que resuelve?


1
IoC! = Evento impulsado. Las similitudes (y en algunos casos se superponen), pero no son principalmente el mismo paradigma.
The Awnry Bear

Buena pregunta. La programación dirigida por eventos es ciertamente IoC. Escribimos controladores de eventos y se los llama desde el bucle de eventos. Pero, IoC es un concepto más genérico que la programación dirigida por eventos. Si anula un método en la subclase, también es un tipo de IoC. Usted escribe un código que se invocaría cuando se usara la referencia apropiada (instancia).
vi.su.

15

Inversión de control es cuando vas al supermercado y tu esposa te da la lista de productos para comprar.

En términos de programación, pasó una función de devolución de llamada getProductList()a la función que está ejecutando:doShopping() .

Permite al usuario de la función definir algunas partes de la misma, haciéndola más flexible.


55
Mi esposa generalmente compra conmigo, pero estoy de acuerdo con esta declaración.
ha9u63ar

1
@ ha9u63ar ¿Tu esposa compra contigo? Bueno, eso se llama agregación entonces.
Julian

2
Si ella también da el dinero, se llama DI.
San

1
La palabra Inversión, al revés, surgió, cuando su esposa lo llama getProductList()para encontrar la fuente de dinero, significa que el control está a su lado. En el caso de la inversión, ella controlará, significa el dinero que también proporcionará para comprar.
San

13

Encontré un ejemplo muy claro aquí que explica cómo se 'invierte el control'.

Código clásico (sin inyección de dependencia)

Así es como un código que no usa DI funcionará aproximadamente:

  • La aplicación necesita Foo (por ejemplo, un controlador), entonces:
  • Aplicación crea Foo
  • La aplicación llama a Foo
    • Foo necesita Bar (por ejemplo, un servicio), entonces:
    • Foo crea Bar
    • Foo llama a Bar
      • Bar necesita Bim (un servicio, un repositorio, ...), entonces:
      • Bar crea Bim
      • Bar hace algo

Usando inyección de dependencia

Así es como un código que usa DI funcionará aproximadamente:

  • La aplicación necesita Foo, que necesita Bar, que necesita Bim, entonces:
  • Aplicación crea Bim
  • La aplicación crea Bar y le da Bim
  • La aplicación crea Foo y le da Bar
  • La aplicación llama a Foo
    • Foo llama a Bar
      • Bar hace algo

El control de las dependencias se invierte de una llamada a la que llama.

¿Qué problemas resuelve?

La inyección de dependencia facilita el intercambio con la implementación diferente de las clases inyectadas. Mientras realiza las pruebas unitarias, puede inyectar una implementación ficticia, lo que hace que las pruebas sean mucho más fáciles.

Por ejemplo: suponga que su aplicación almacena el archivo subido por el usuario en Google Drive, con DI su código de controlador puede verse así:

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) {}
}

Cuando sus requisitos cambien, por ejemplo, en lugar de GoogleDrive, se le pedirá que use Dropbox. Solo necesita escribir una implementación de Dropbox para StorageServiceInterface. No debe realizar ningún cambio en el controlador siempre que la implementación de Dropbox se adhiera a StorageServiceInterface.

Durante la prueba, puede crear el simulacro para StorageServiceInterface con la implementación ficticia donde todos los métodos devuelven nulo (o cualquier valor predefinido según su requisito de prueba).

En cambio, si tuviera la clase de controlador para construir el objeto de almacenamiento con la newpalabra clave como esta:

class SomeController
{
    private $storage;

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

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

Cuando desee cambiar con la implementación de Dropbox, debe reemplazar todas las líneas donde new construye el objeto GoogleDriveService y usar DropboxService. Además, al probar la clase SomeController, el constructor siempre espera la clase GoogleDriveService y se activan los métodos reales de esta clase.

¿Cuándo es apropiado y cuándo no? En mi opinión, usas DI cuando crees que hay (o puede haber) implementaciones alternativas de una clase.


Esta debería ser la respuesta más correcta ya que es la única que explica cómo se invierte el "control".
Yarimadam

mejor explicación hasta ahora
Ali80

12

Una explicación escrita muy simple se puede encontrar aquí

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

Dice -

"Cualquier aplicación no trivial se compone de dos o más clases que colaboran entre sí para realizar una lógica empresarial. Tradicionalmente, cada objeto es responsable de obtener sus propias referencias a los objetos con los que colabora (sus dependencias). Al aplicar DI, el los objetos reciben sus dependencias en el momento de la creación por parte de una entidad externa que coordina cada objeto en el sistema. En otras palabras, las dependencias se inyectan en los objetos ".


12

La inversión de control es un principio genérico, mientras que la inyección de dependencia se da cuenta de este principio como un patrón de diseño para la construcción de gráficos de objetos (es decir, la configuración controla cómo los objetos se hacen referencia entre sí, en lugar de que el objeto mismo controle cómo obtener la referencia a otro objeto).

Mirando a la Inversión de Control como un patrón de diseño, tenemos que mirar lo que estamos invirtiendo. La inyección de dependencia invierte el control de construir un gráfico de objetos. Si se dice en términos simples, la inversión de control implica un cambio en el flujo de control en el programa. P.ej. En la aplicación independiente tradicional, tenemos el método principal, desde donde el control se pasa a otras bibliotecas de terceros (en caso de que hayamos utilizado la función de biblioteca de terceros), pero a través de la inversión del control de control se transfiere del código de la biblioteca de terceros a nuestro código , ya que estamos tomando el servicio de una biblioteca de terceros. Pero hay otros aspectos que deben invertirse dentro de un programa, por ejemplo, invocación de métodos y subprocesos para ejecutar el código.

Para aquellos interesados ​​en profundizar en la Inversión de Control, se ha publicado un documento que describe una imagen más completa de la Inversión de Control como patrón de diseño (OfficeFloor: uso de patrones de oficina para mejorar el diseño del software http://doi.acm.org/10.1145/ 2739011.2739013 con una copia gratuita disponible para descargar desde http://www.officefloor.net/about.html ).

Lo que se identifica es la siguiente relación:

Inversión de control (para métodos) = Dependencia (estado) Inyección + Inyección de continuación + Inyección de hilo

Resumen de la relación anterior para la Inversión de control disponible: http://dzone.com/articles/inversion-of-coupling-control


Esta es una respuesta muy clara. Gracias por la explicación.
KunYu Tsai

11

IoC se trata de invertir la relación entre su código y el código de terceros (biblioteca / marco):

  • En el desarrollo normal de s / w, usted escribe el método main () y llama a los métodos de "biblioteca". Tú tienes el control :)
  • En IoC, el "marco" controla main () y llama a sus métodos. El marco está en control :(

DI (Inyección de dependencias) trata sobre cómo fluye el control en la aplicación. La aplicación de escritorio tradicional tenía flujo de control desde su aplicación (método main ()) a otras llamadas a métodos de biblioteca, pero con el flujo de control DI invertido, ese marco se encarga de iniciar su aplicación, inicializarla e invocar sus métodos siempre que sea necesario.

Al final siempre ganas :)


10

Me gusta esta explicación: http://joelabrahamsson.com/inversion-of-control-an-introduction-with-examples-in-net/

Comienza simple y muestra ejemplos de código también.

ingrese la descripción de la imagen aquí

El consumidor, X, necesita la clase consumida, Y, para lograr algo. Todo eso es bueno y natural, pero ¿X realmente necesita saber que usa Y?

¿No es suficiente que X sepa que usa algo que tiene el comportamiento, los métodos, las propiedades, etc. de Y sin saber quién implementa realmente el comportamiento?

Al extraer una definición abstracta del comportamiento utilizado por X en Y, ilustrado como I a continuación, y dejar que el consumidor X use una instancia de eso en lugar de Y, puede continuar haciendo lo que hace sin tener que conocer los detalles sobre Y.

ingrese la descripción de la imagen aquí

En la ilustración anterior, Y implementa I y X usa una instancia de I. Si bien es bastante posible que X todavía use Y, lo interesante es que X no lo sabe. Simplemente sabe que usa algo que implementa I.

Lea el artículo para obtener más información y descripción de beneficios como:

  • X ya no depende de Y
  • Más flexible, la implementación se puede decidir en tiempo de ejecución
  • Aislamiento de la unidad de código, prueba más fácil

...


El enlace es muy útil. Muchas gracias :)
M Fuat NUROĞLU

10

Entiendo que la respuesta ya se ha dado aquí. Pero sigo pensando que algunos conceptos básicos sobre la inversión del control tienen que ser discutidos aquí en detalle para futuros lectores.

La Inversión de Control (IoC) se ha construido sobre un principio muy simple llamado Principio de Hollywood . Y dice que

No nos llames, te llamaremos

Lo que significa es que no vayas a Hollywood para cumplir tu sueño, sino que si eres digno, Hollywood te encontrará y hará que tu sueño se haga realidad. Bastante invertido, ¿eh?

Ahora, cuando discutimos sobre el principio de IoC, solemos olvidarnos de Hollywood. Para IoC, tiene que haber tres elementos, un Hollywood, usted y una tarea como cumplir su sueño.

En nuestro mundo de programación, Hollywood representa un marco genérico (puede ser escrito por usted u otra persona), usted representa el código de usuario que escribió y la tarea representa lo que desea lograr con su código. ¡Ahora nunca va a activar su tarea usted mismo, no en IoC! Por el contrario, ha diseñado todo de tal manera que su marco desencadenará su tarea por usted. Por lo tanto, ha creado un marco reutilizable que puede hacer que alguien sea un héroe u otro un villano. Pero ese marco siempre está a cargo, sabe cuándo elegir a alguien y que alguien solo sabe lo que quiere ser.

Aquí se daría un ejemplo de la vida real. Supongamos que desea desarrollar una aplicación web. Entonces, crea un marco que manejará todas las cosas comunes que una aplicación web debe manejar, como manejar la solicitud http, crear el menú de la aplicación, servir páginas, administrar cookies, desencadenar eventos, etc.

Y luego deja algunos enganches en su marco donde puede poner más códigos para generar menús personalizados, páginas, cookies o registrar algunos eventos del usuario, etc. En cada solicitud del navegador, su marco se ejecutará y ejecutará sus códigos personalizados si está enganchado y luego lo devolverá al navegador

Entonces, la idea es bastante simple. En lugar de crear una aplicación de usuario que controle todo, primero cree un marco reutilizable que controle todo, luego escriba sus códigos personalizados y conéctelos al marco para ejecutarlos a tiempo.

Laravel y EJB son ejemplos de tales marcos.

Referencia:

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

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


1
La respuesta más apropiada que encontré aquí.
blueray

8

Programación hablando

IoC en términos sencillos: es el uso de la interfaz como una forma de algo específico (como un campo o un parámetro) como comodín que pueden usar algunas clases. Permite la reutilización del código.

Por ejemplo, digamos que tenemos dos clases: perro y gato . Ambos comparten las mismas cualidades / estados: edad, tamaño, peso. Entonces, en lugar de crear una clase de servicio llamada DogService y CatService , puedo crear una sola llamada AnimalService que permita usar Dog y Cat solo si usan la interfaz IAnimal .

Sin embargo, pragmáticamente hablando, tiene algo al revés.

a) La mayoría de los desarrolladores no saben cómo usarlo . Por ejemplo, puedo crear una clase llamada Cliente y puedo crear automáticamente (usando las herramientas del IDE) una interfaz llamada ICustomer . Por lo tanto, no es raro encontrar una carpeta llena de clases e interfaces, sin importar si las interfaces se reutilizarán o no. Se llama BLOATED. Algunas personas podrían argumentar que "puede ser en el futuro que podamos usarlo". : - |

b) Tiene algunos límites. Por ejemplo, hablemos del caso de Dog and Cat y quiero agregar un nuevo servicio (funcionalidad) solo para perros. Digamos que quiero calcular la cantidad de días que necesito para entrenar a un perro ( trainDays()), para el gato es inútil, los gatos no pueden ser entrenados (estoy bromeando).

b.1) Si agrego trainDays()al Servicio AnimalService , también funciona con gatos y no es válido en absoluto.

b.2) Puedo agregar una condición en la trainDays()que evalúa qué clase se utiliza. Pero romperá completamente el IoC.

b.3) Puedo crear una nueva clase de servicio llamada DogService solo para la nueva funcionalidad. Pero aumentará la capacidad de mantenimiento del código porque tendremos dos clases de servicio (con una funcionalidad similar) para Dog y es malo.


Acerca de las clases / interfaces hinchadas: no siempre tiene que reutilizar todas las interfaces. A veces tiene sentido dividir una interfaz grande en muchas más pequeñas para ver sus límites funcionales. Las interfaces más pequeñas también son más fáciles de reutilizar en otras implementaciones. También lo alienta a codificar en una interfaz donde sea que tenga sentido. Considere "Segregación de interfaz". Solo porque está utilizando una interfaz no significa que esté desacoplado. Una única interfaz gorda es inútil. - Solo mis 2 centavos :)
MK

7

He leído muchas respuestas para esto, pero si alguien todavía está confundido y necesita un "término laico" más ultra para explicar IoC, aquí está mi opinión:

Imagine a un padre y un niño hablando entre ellos.

Sin IoC:

* Padre : solo puedes hablar cuando te hago preguntas y solo puedes actuar cuando te doy permiso.

Padre : Esto significa que no puedes preguntarme si puedes comer, jugar, ir al baño o incluso dormir si no te pregunto.

Padre : ¿Quieres comer?

Niño : No.

Padre : Está bien, volveré. Espérame.

Niño : (Quiere jugar pero como no hay preguntas de los padres, el niño no puede hacer nada).

Después de 1 hora...

Padre : estoy de vuelta. ¿Quieres jugar?

Niño : si.

Padre : Permiso otorgado.

Niño : (finalmente puede jugar).

Este escenario simple explica que el control está centrado en el padre. La libertad del niño está restringida y depende en gran medida de la pregunta de los padres. El niño SOLO puede hablar cuando se le pide que hable, y SOLO puede actuar cuando se le concede permiso.

Con IoC:

El niño ahora tiene la capacidad de hacer preguntas y el padre puede responder con respuestas y permisos. ¡Simplemente significa que el control está invertido! El niño ahora es libre de hacer preguntas en cualquier momento y aunque todavía existe dependencia con el padre con respecto a los permisos, no depende de los medios para hablar / hacer preguntas.

En una forma tecnológica de explicar, esto es muy similar a la interacción consola / shell / cmd vs GUI. (Cuál es la respuesta de Mark Harrison arriba de la respuesta superior n. ° 2). En la consola, depende de lo que se le pide / muestra y no puede saltar a otros menús y funciones sin responder primero a su pregunta; siguiendo un flujo secuencial estricto. (programáticamente esto es como un método / bucle de función). Sin embargo, con la GUI, los menús y las funciones se presentan y el usuario puede seleccionar lo que necesite para tener más control y estar menos restringido. (mediante programación, los menús tienen devolución de llamada cuando se seleccionan y se lleva a cabo una acción).


6

La inversión del control se trata de transferir el control de la biblioteca al cliente. Tiene más sentido cuando hablamos de un cliente que inyecta (pasa) un valor de función (expresión lambda) en una función de orden superior (función de biblioteca) que controla (cambia) el comportamiento de la función de biblioteca. Un cliente o marco que inyecta dependencias de la biblioteca (que portan comportamiento) en las bibliotecas también puede considerarse IoC


5

Como ya hay muchas respuestas para la pregunta, pero ninguna de ellas muestra el desglose del término Control de inversión, veo la oportunidad de dar una respuesta más concisa y útil.

La inversión de control es un patrón que implementa el principio de inversión de dependencia (DIP). DIP establece lo siguiente: 1. Los módulos de alto nivel no deberían depender de módulos de bajo nivel. Ambos deberían depender de abstracciones (por ejemplo, interfaces). 2. Las abstracciones no deberían depender de los detalles. Los detalles (implementaciones concretas) deben depender de abstracciones.

Hay tres tipos de inversión de control:

Los proveedores de inversión de interfaz no deberían definir una interfaz. En cambio, el consumidor debe definir la interfaz y los proveedores deben implementarla. La inversión de interfaz permite eliminar la necesidad de modificar al consumidor cada vez que se agrega un nuevo proveedor.

Inversión de flujo Cambia el control del flujo. Por ejemplo, tiene una aplicación de consola en la que solicitó ingresar muchos parámetros y después de cada parámetro ingresado se ve obligado a presionar Enter. Puede aplicar Flow Inversion aquí e implementar una aplicación de escritorio donde el usuario puede elegir la secuencia de entrada de parámetros, el usuario puede editar parámetros y, en el paso final, el usuario necesita presionar Enter solo una vez.

Creación de inversión Se puede implementar mediante los siguientes patrones: Patrón de fábrica, Localizador de servicios e Inyección de dependencias. La inversión de creación ayuda a eliminar las dependencias entre tipos que mueven el proceso de creación de objetos de dependencia fuera del tipo que usa estos objetos de dependencia. ¿Por qué las dependencias son malas? Aquí hay un par de ejemplos: la creación directa de un nuevo objeto en su código dificulta las pruebas; es imposible cambiar las referencias en ensamblajes sin recompilación (violación del principio OCP); no puede reemplazar fácilmente una interfaz de usuario de escritorio por una interfaz de usuario web.


3
  1. Entonces el número 1 arriba . ¿Qué es la inversión de control?

  2. El mantenimiento es lo primero que me resuelve. Garantiza que estoy usando interfaces para que dos clases no sean íntimas entre sí.

Al usar un contenedor como Castle Windsor, resuelve los problemas de mantenimiento aún mejor. Poder cambiar un componente que va a una base de datos por uno que usa persistencia basada en archivos sin cambiar una línea de código es increíble (cambio de configuración, ya está).

Y una vez que entras en genéricos, se pone aún mejor. Imagine tener un editor de mensajes que recibe registros y publica mensajes. No le importa lo que publica, pero necesita un mapeador para llevar algo de un registro a un mensaje.

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

Lo escribí una vez, pero ahora puedo inyectar muchos tipos en este conjunto de código si publico diferentes tipos de mensajes. También puedo escribir mapeadores que toman un registro del mismo tipo y los asignan a diferentes mensajes. Usar DI con genéricos me ha dado la capacidad de escribir muy poco código para realizar muchas tareas.

Ah, sí, hay problemas de comprobabilidad, pero son secundarios a los beneficios de IoC / DI.

Definitivamente estoy amando IoC / DI.

3) Se vuelve más apropiado en el momento en que tiene un proyecto de tamaño mediano y algo más complejo. Diría que se vuelve apropiado en el momento en que empiezas a sentir dolor.



3

La creación de un objeto dentro de la clase se denomina acoplamiento cerrado, Spring elimina esta dependencia siguiendo un patrón de diseño (DI / IOC). En qué objeto de clase se pasa en constructor en lugar de crear en clase. Además, damos una variable de referencia de superclase en el constructor para definir una estructura más general.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.