Prefacio
En este capítulo, vamos a explicar el quinto capítulo de la implementación de los cinco principios principales del lenguaje sólido de JavaScript, que es el LSP (el principio de inversión de dependencia).
Texto en inglés original: http://freshbrewedcode.com/derekgreeer/2012/01/22/solid-javascript-the-dependency-inversion-principle/
Principio de inversión de confianza
La descripción del principio de inversión de dependencia es:
A. Los módulos de alto nivel no deben depender de módulos de bajo nivel. Ambos deberían depender de las abstracciones.
Los módulos de alto nivel no deben depender de los módulos de bajo nivel, ambos deben confiar en la abstracción
B. Las abstracciones no deben depender de los detalles. Los detalles deben depender de las abstracciones.
El resumen no debe depender de los detalles, los detalles deben depender de la abstracción
El problema más importante con el principio de inversión de dependencia es garantizar que los componentes principales de la aplicación o marco se desacople a partir de los detalles de implementación de los componentes subyacentes no importantes, lo que garantizará que las partes más importantes del programa no se vean afectadas por los cambios y las modificaciones de los componentes de bajo nivel.
La primera parte de este principio es sobre el acoplamiento entre los módulos de alto nivel y los módulos de bajo nivel. En la arquitectura de división tradicional, los módulos de alto nivel (encapsulan la lógica comercial central del programa) siempre confían en algunos módulos de bajo nivel (algunos puntos básicos). Cuando se aplica el principio de inversión de dependencia, la relación se invierte. A diferencia de los módulos de alto nivel que se basan en módulos de bajo nivel, la inversión de dependencia hace que los módulos de bajo nivel se basen en interfaces definidas en módulos de alto nivel. Por ejemplo, si desea persistir datos para un programa, el diseño tradicional es que el módulo central depende de la API de un módulo persistente. Después de la reconstrucción de acuerdo con el principio de inversión de dependencia, el módulo central debe definir una interfaz API persistente, y luego la instancia de implementación persistente debe implementar la interfaz API definida por el módulo central.
La segunda parte de este principio describe la relación correcta entre abstracción y detalle. Comprender esta parte es más útil al comprender el lenguaje C ++ porque su aplicabilidad es más obvia.
A diferencia de algunos idiomas escrita estáticamente, C ++ no proporciona un concepto a nivel de lenguaje para definir interfaces. ¿Cuál es la relación entre la definición de clase y la implementación de clase? En C ++, las clases se definen en forma de archivos de encabezado, que definen los métodos y variables del miembro de la clase que el archivo fuente necesita implementar. Debido a que todas las variables y métodos privados se definen en el archivo de encabezado, se pueden usar para abstraerlos y desacoplarlas antes de los detalles de implementación. El concepto de interfaz se implementa definiendo solo métodos abstractos (la clase base abstracta en C ++) se utiliza para implementar clases.
Dip y JavaScript
Debido a que JavaScript es un lenguaje dinámico, no hay necesidad de abstraer para el desacoplamiento. Por lo tanto, la abstracción no debe confiar en los detalles. Este cambio no tiene mucho impacto en JavaScript, pero los módulos de alto nivel no deberían depender de módulos de bajo nivel, sino que tienen un gran impacto.
Al discutir el principio de la inversión de dependencia en el contexto de los idiomas escrita estáticamente, los conceptos de acoplamiento incluyen semántico y físico. Esto significa que si un módulo de alto nivel depende de un módulo de bajo nivel, no solo combina la interfaz semántica, sino también de la interfaz física definida en el módulo subyacente. En otras palabras, los módulos de alto nivel no solo deben desacoplarse de la biblioteca de terceros, sino también de módulos nativos de bajo nivel.
Para explicar esto, imagine que un programa .NET podría contener un módulo de alto nivel muy útil que se basa en un módulo persistente de bajo nivel. Cuando el autor necesita agregar una interfaz similar a la API de persistencia, independientemente de si el principio de inversión de dependencia se usa o no, los módulos de alto nivel no se pueden reutilizar en otros programas antes de volver a implementar la nueva interfaz de este módulo de bajo nivel.
En JavaScript, la aplicabilidad del principio de inversión de dependencia se limita al acoplamiento semántico entre los módulos de alto nivel y los módulos de bajo nivel. Por ejemplo, DIP puede agregar interfaces según sea necesario en lugar de acoplar interfaces implícitas definidas por módulos de bajo nivel.
Para entender esto, echemos un vistazo al siguiente ejemplo:
La copia del código es la siguiente:
$ .fn.trackmap = function (opciones) {
Var predeterminados = {
/ * valores predeterminados */
};
opciones = $ .extend ({}, predeterminados, opciones);
var mapOptions = {
Centro: nuevo google.maps.latlng (opciones.latitude, opciones. Longitud),
Zoom: 12,
MapTypeid: Google.Maps.MapTypeid.Roadmap
},
map = nuevo Google.maps.map (this [0], mapOptions),
pos = nuevo Google.maps.latlng (options.latitude, options.nongitude);
var marcador = nuevo google.maps.marker ({
Posición: POS,
Título: Options.title,
icono: options.icon
});
Marker.setMap (mapa);
options.feed.update (función (latitud, longitud) {
Marker.setMap (nulo);
var newLatlng = new Google.maps.latlng (latitud, longitud);
marker.position = newLatlng;
Marker.setMap (mapa);
map.setCenter (newlatlng);
});
devolver esto;
};
var updater = (function () {
// Propiedades privadas
devolver {
Actualización: function (devolución de llamada) {
UpdateMap = Callback;
}
};
}) ();
$ ("#map_canvas"). TrackMap ({
Latitud: 35.044640193770725,
Longitud: -89.98193264007568,
icono: 'http://bit.ly/zjngde',
Título: 'Número de seguimiento: 12345',
Feed: actualizador
});
En el código anterior, hay una pequeña biblioteca de clases JS que convierte un DIV en un mapa para mostrar la información de ubicación rastreada actualmente. La función TrackMap tiene 2 dependencias: la API de Google Maps de terceros y la alimentación de ubicación. La responsabilidad del objeto de alimentación es llamar a una devolución de llamada (proporcionada en la inicialización) cuando se actualiza la posición del icono y pase en la latitud de latitud y la longitud de precisión. La API de Google Maps se usa para representar interfaces.
La interfaz del objeto de alimentación puede basarse en la instalación o no diseñada de acuerdo con los requisitos de la función de mapa de seguimiento de instalación. De hecho, su papel es muy simple, centrado en implementaciones simples y diferentes y no necesita confiar tanto en Google Maps. La semántica de TrackMap está acoplada a la API de Google Maps. Si necesita cambiar a diferentes proveedores de mapas, debe reescribir la función TrackMap para que pueda adaptarse a diferentes proveedores.
Para voltear el acoplamiento semántico de la biblioteca de clases de Google Maps, necesitamos reescribir la función de diseño de mapa de seguridad para acoplar una interfaz implícita (resumir la interfaz del proveedor del proveedor de mapas). También necesitamos un objeto de implementación que esté adaptado a la API de Google Maps. La siguiente es la función de TrackMap refactorizada:
La copia del código es la siguiente:
$ .fn.trackmap = function (opciones) {
Var predeterminados = {
/ * valores predeterminados */
};
opciones = $ .extend ({}, predeterminados, opciones);
options.provider.showmap (
esto [0],
opciones.latitud,
opciones. Longitud,
opciones.icon,
options.title);
options.feed.update (función (latitud, longitud) {
opciones.provider.updateMap (latitud, longitud);
});
devolver esto;
};
$ ("#map_canvas"). TrackMap ({
Latitud: 35.044640193770725,
Longitud: -89.98193264007568,
icono: 'http://bit.ly/zjngde',
Título: 'Número de seguimiento: 12345',
Feed: Updater,
Proveedor: TrackMap.googlemapsProvider
});
En esta versión, rediseñamos la función TrackMap y la interfaz del proveedor de mapas requerida, y luego movimos los detalles de implementación a un componente separado de GOOGLEMAPSPROVEVER, que puede estar encapsulado de forma independiente en un módulo JavaScript separado. Aquí está mi implementación de GOOGLEMAPSPROVIDER:
La copia del código es la siguiente:
TrackMap.GoogLEMapsProvider = (function () {
marcador var, mapa;
devolver {
showmap: función (elemento, latitud, longitud, icono, título) {
var mapOptions = {
Centro: nuevo Google.maps.latlng (latitud, longitud),
Zoom: 12,
MapTypeid: Google.Maps.MapTypeid.Roadmap
},
pos = nuevo Google.maps.latlng (latitud, longitud);
map = nuevo Google.Maps.Map (Element, MapOptions);
marcador = nuevo Google.Maps.Marker ({
Posición: POS,
Título: Título,
icono: icono
});
Marker.setMap (mapa);
},
UpdateMap: function (latitud, longitud) {
Marker.setMap (nulo);
var newLatlng = new Google.maps.latlng (latitud, longitud);
marker.position = newLatlng;
Marker.setMap (mapa);
map.setCenter (newlatlng);
}
};
}) ();
Después de realizar los cambios anteriores, la función TrackMap se volverá muy flexible y no tendrá que confiar en la API de Google Maps. En cambio, otros proveedores de mapas pueden ser reemplazados a voluntad, es decir, cualquier proveedor de mapas puede adaptarse de acuerdo con las necesidades del programa.
¿Cuándo es la inyección de dependencia?
No está relacionado. De hecho, el concepto de inyección de dependencia a menudo se mezcla con el principio de inversión de dependencia. Para aclarar esta diferencia, es necesario explicar:
La inyección de dependencia es una forma especial de inversión de control, y la inversión significa cómo un componente adquiere sus dependencias. Inyección de dependencia significa: la dependencia se proporciona al componente, en lugar del componente para obtener la dependencia, lo que significa crear una instancia de la dependencia, solicitar la dependencia a través de la fábrica y solicitar la dependencia a través del localización del servicio o el componente mismo. El principio de inversión de dependencia y la inyección de dependencia se centran en las dependencias y se utilizan para la inversión. Sin embargo, el principio de inversión de dependencia no se centra en cómo los componentes adquieren dependencias, sino solo en cómo los módulos de alto nivel se desacoplan de los módulos de bajo nivel. En cierto sentido, el principio de inversión de dependencia es otra forma de inversión de control. Aquí, la inversión es qué módulo define la interfaz (definida desde el nivel inferior, la inversión al nivel superior).
Resumir
Este es el último artículo de los cinco principios principales. En estos 5 artículos, vemos cómo se implementa sólido en JavaScript. Se explican diferentes principios desde diferentes ángulos en JavaScript. (Nota del tío: de hecho, creo que aunque es un poco inapropiado, desde otra perspectiva, los principios generales son en realidad los mismos en varios idiomas).