En ingeniería de software , la inversión de control ( IoC ) es un principio de diseño en el que partes personalizadas de un programa informático reciben el flujo de control de una fuente externa (por ejemplo, un marco ). El término "inversión" es histórico: una arquitectura de software con este diseño "invierte" el control en comparación con la programación procedimental . En la programación procedimental, el código personalizado de un programa llama a bibliotecas reutilizables para encargarse de tareas genéricas, pero con la inversión de control, es la fuente externa o el marco el que llama al código personalizado.
La inversión de control ha sido ampliamente utilizada por los marcos de desarrollo de aplicaciones desde el surgimiento de los entornos GUI [1] [2] y continúa utilizándose tanto en entornos GUI como en marcos de aplicaciones de servidores web . La inversión de control hace que el marco sea extensible mediante los métodos definidos por el programador de la aplicación. [3]
La programación basada en eventos se suele implementar mediante IoC, de modo que el código personalizado solo tiene que ocuparse del manejo de eventos, mientras que el bucle de eventos y el envío de eventos/mensajes lo gestiona el marco o el entorno de ejecución. En los marcos de aplicaciones de servidor web, el envío suele denominarse enrutamiento y los controladores pueden denominarse puntos finales.
La frase "inversión de control" también ha llegado a usarse por separado en la comunidad de programadores Java para referirse específicamente a los patrones de inyección de dependencia (pasar a los objetos los servicios que necesitan) que ocurren con los "contenedores IoC" en los marcos Java como el marco Spring . [4] En este sentido diferente, "inversión de control" se refiere a otorgar al marco control sobre las implementaciones de dependencias que son utilizadas por los objetos de la aplicación [5] en lugar del significado original de otorgar al marco flujo de control (control sobre el tiempo de ejecución del código de la aplicación, por ejemplo, devoluciones de llamadas).
Como ejemplo, con la programación tradicional, la función principal de una aplicación podría realizar llamadas de función a una biblioteca de menú para mostrar una lista de comandos disponibles y solicitar al usuario que seleccione uno. [6] De esta manera, la biblioteca devolvería la opción elegida como el valor de la llamada de función, y la función principal utiliza este valor para ejecutar el comando asociado. Este estilo era común en las interfaces basadas en texto . Por ejemplo, un cliente de correo electrónico puede mostrar una pantalla con comandos para cargar un correo nuevo, responder el correo actual, crear un correo nuevo, etc., y la ejecución del programa se bloquearía hasta que el usuario presione una tecla para seleccionar un comando.
Por otra parte, con la inversión de control, el programa se escribiría utilizando un marco de software que conoce elementos gráficos y de comportamiento comunes, como sistemas de ventanas , menús, control del ratón, etc. El código personalizado "rellena los espacios en blanco" para el marco, como proporcionar una tabla de elementos de menú y registrar una subrutina de código para cada elemento, pero es el marco el que supervisa las acciones del usuario e invoca la subrutina cuando se selecciona un elemento de menú. En el ejemplo del cliente de correo, el marco podría seguir las entradas del teclado y del ratón y llamar al comando invocado por el usuario por cualquiera de los medios y, al mismo tiempo, supervisar la interfaz de red para averiguar si llegan nuevos mensajes y actualizar la pantalla cuando se detecta alguna actividad de red. El mismo marco podría utilizarse como esqueleto para un programa de hoja de cálculo o un editor de texto. Por el contrario, el marco no sabe nada sobre navegadores web, hojas de cálculo o editores de texto; implementar su funcionalidad requiere un código personalizado.
La inversión de control conlleva la fuerte connotación de que el código reutilizable y el código específico del problema se desarrollan de forma independiente aunque operen juntos en una aplicación. Las devoluciones de llamadas , los programadores , los bucles de eventos y el método de plantilla son ejemplos de patrones de diseño que siguen el principio de inversión de control, aunque el término se utiliza más comúnmente en el contexto de la programación orientada a objetos . ( La inyección de dependencias es un ejemplo de la idea separada y específica de "invertir el control sobre las implementaciones de dependencias" popularizada por los marcos de Java). [4]
A la inversión de control a veces se la denomina el "Principio de Hollywood: no nos llame, le llamaremos nosotros". [1]
La inversión de control no es un término nuevo en informática. Martin Fowler remonta la etimología de la frase a 1988, [7] pero está estrechamente relacionada con el concepto de inversión de programa descrito por Michael Jackson en su metodología Jackson Structured Programming en la década de 1970. [8] Un analizador sintáctico ascendente puede verse como una inversión de un analizador sintáctico descendente : en un caso, el control recae en el analizador sintáctico, mientras que en el otro caso, recae en la aplicación receptora.
El término fue utilizado por Michael Mattsson en una tesis (con su significado original de un marco que llama al código de la aplicación en lugar de viceversa) [9] y luego fue tomado de allí [10] por Stefano Mazzocchi y popularizado por él en 1999 en un proyecto extinto de la Apache Software Foundation, Avalon, en el que se refería a un objeto padre que pasaba las dependencias de un objeto hijo además de controlar el flujo de ejecución. [11] La frase se popularizó aún más en 2004 por Robert C. Martin y Martin Fowler , el último de los cuales rastrea los orígenes del término a la década de 1980. [7]
En la programación tradicional, el flujo de la lógica empresarial está determinado por objetos que están enlazados estáticamente entre sí. Con la inversión de control, el flujo depende del gráfico de objetos que se construye durante la ejecución del programa. Este flujo dinámico es posible gracias a las interacciones de los objetos que se definen mediante abstracciones. Esta vinculación en tiempo de ejecución se logra mediante mecanismos como la inyección de dependencias o un localizador de servicios . En IoC, el código también podría estar enlazado estáticamente durante la compilación, pero encontrando el código a ejecutar leyendo su descripción desde la configuración externa en lugar de con una referencia directa en el código mismo.
En la inyección de dependencia, un objeto o módulo dependiente se acopla al objeto que necesita en tiempo de ejecución . Normalmente, no es posible saber en tiempo de compilación qué objeto en particular satisfará la dependencia durante la ejecución del programa mediante el análisis estático . Si bien aquí se describe en términos de interacción de objetos, el principio se puede aplicar a otras metodologías de programación además de la programación orientada a objetos .
Para que el programa en ejecución vincule objetos entre sí, estos deben poseer interfaces compatibles . Por ejemplo, la clase A
puede delegar un comportamiento a una interfaz I
que implementa la clase B
; el programa crea una instancia A
de y B
y luego inyecta B
en A
.
Los navegadores web implementan la inversión de control para eventos DOM en HTML. El desarrollador de aplicaciones utiliza esta función document.addEventListener()
para registrar una devolución de llamada.
<!doctype html> < html lang = "en" > < head > < meta charset = "utf-8" > < title > DOM Nivel 2 </ title > </ head > < body > < h1 > Controlador de eventos DOM Nivel 2 </ h1 > < p >< large >< span id = "output" ></ span ></ large ></ p > < script > var registerListener = function () { document . getElementById ( "output" ). innerHTML = "<large>Se llamó al oyente registrado.</large>" ; } document . addEventListener ( "click" , registerListener , true ); document . getElementById ( "output" ). innerHTML = "<large>El controlador de eventos ha sido registrado. Si hace clic en la página, su navegador web llamará al controlador de eventos.</large>" </script> </cuerpo> </html>
Este código de ejemplo para una aplicación web ASP.NET Core crea un host de aplicación web, registra un punto final y luego pasa el control al marco: [12]
var builder = WebApplication . CreateBuilder ( args ); var app = builder . Build (); app . MapGet ( "/" , () => "¡Hola mundo!" ); app . Run ();
El enrutamiento es responsable de hacer coincidir las solicitudes HTTP entrantes y enviarlas a los puntos finales ejecutables de la aplicación. Los puntos finales son las unidades de código ejecutable de manejo de solicitudes de la aplicación. Los puntos finales se definen en la aplicación y se configuran cuando esta se inicia.
{{cite web}}
: CS1 maint: varios nombres: lista de autores ( enlace )