Este equipo de especialistas luego de varios días de investigación y recopilación de de datos, dimos con los datos necesarios, nuestro deseo es que resulte de gran utilidad en tu plan.
Solución:
Yo diría que el DIP se aplica en JavaScript de la misma manera que se aplica en la mayoría de los lenguajes de programación, pero debe ser consciente del papel de la escritura pato. Hagamos un ejemplo para ver a qué me refiero …
Digamos que quiero ponerme en contacto con el servidor para obtener algunos datos. Sin aplicar DIP, esto podría verse así:
$.get("/address/to/data", function (data)
$("#thingy1").text(data.property1);
$("#thingy2").text(data.property2);
);
Con DIP, podría escribir código como
fillFromServer("/address/to/data", thingyView);
donde la abstraccion fillFromServer
pueden para el caso particular en el que queremos usar el Ajax de jQuery ser implementado como
function fillFromServer(url, view)
$.get(url, function (data)
view.setValues(data);
);
y la abstraccion view
puede ser implementado para el caso particular de una vista basada en elementos con ID thingy1
y thingy2
como
var thingyView =
setValues: function (data)
$("#thingy1").text(data.property1);
$("#thingy2").text(data.property2);
;
Principio A:
fillFromServer
pertenece a un módulo de bajo nivel, manejando como lo hace la interacción de bajo nivel entre el servidor y la vista. Algo como, digamos, unsettingsUpdater
objeto sería parte de un módulo de nivel superior, y se basaría en elfillFromServer
abstracción — no en los detalles de la misma, que en este caso se implementan a través de jQuery.- Similar,
fillFromServer
no depende de detalles específicos de los elementos DOM y sus ID para realizar su trabajo; en cambio, depende de la abstracción de unview
, que para sus efectos es cualquier tipo que tenga unsetValues
método. (Esto es lo que se entiende por “tipeo de pato”).
Principio B:
Esto es un poco menos fácil de ver en JavaScript, con su escritura pato; en particular, algo como view
no deriva de (es decir, depende de) algún tipo de viewInterface
escribe. Pero podemos decir que nuestro caso particular, el thingyView
, es un detalle que “depende” de la abstracción view
.
Siendo realistas, “depende” del hecho de que las personas que llaman entienden qué tipo de métodos deben llamarse, es decir, que las personas que llaman son consciente de la abstracción apropiada. En los lenguajes orientados a objetos habituales, es más fácil ver la dependencia de thingyView
explícitamente sobre la abstracción en sí. En tales lenguajes, la abstracción estaría incorporada en una interfaz (digamos, IView
en C # o Viewable
en Java), y la dependencia explícita es por herencia (class ThingyView : IView
o class ThingyView implements Viewable
). Sin embargo, se aplica el mismo sentimiento.
¿Por qué es esto genial? Bueno, digamos que un día necesitaba poner los datos del servidor en cuadros de texto con ID text1
y text2
en lugar de s con ID
thingy1
y thingy2
. Además, digamos que este código se llamaba con mucha frecuencia, y la evaluación comparativa reveló que el rendimiento crítico se estaba perdiendo mediante el uso de jQuery. Entonces podría crear una nueva “implementación” del view
abstracción, así:
var textViewNoJQuery =
setValues: function (data)
document.getElementById("text1").value = data.property1;
document.getElementById("text2").value = data.property2;
;
Luego inyecto esta instancia particular de la abstracción de la vista en mi fillFromServer
abstracción:
fillFromServer("/address/to/data", textViewNoJQuery);
Esto requirió no cambios a fillFromServer
código, porque dependía sólo de la abstracción de un view
con un setValues
método, y no en los detalles del DOM y cómo accedemos a él. Esto no solo es satisfactorio porque podemos reutilizar el código, sino que también indica que hemos separado claramente nuestras preocupaciones y creado un código muy preparado para el futuro.
EDITAR:
Esto muestra el uso de DIP en JavaScript sin formato y un menos completo Ejemplo de jQuery. Sin embargo, la siguiente descripción se puede aplicar fácilmente a jQuery. Vea el ejemplo de jQuery en la parte inferior.
La mejor manera es aprovechar el “Patrón de adaptador”, también llamado “envoltorio”.
Un adaptador es básicamente una forma de envolver un objeto o módulo de tal manera que proporciona el mismo interfaz consistente a su dependientes. De esa manera, la clase dependiente (generalmente una nivel más alto class) puede intercambiar fácilmente módulos del mismo tipo.
Un ejemplo de esto sería un alto nivel (o supra) módulo que depende de los módulos Geo / Mapping.
Analicemos esto. Si nuestro módulo supra ya está usando GoogleMaps pero luego la gerencia decide que es más barato optar por LeafletMaps, no queremos tener que reescribir cada llamada de método desde gMap.showMap(user, latLong)
para leaflet.render(apiSecret,latLong, user)
, et al. Sería una pesadilla tener que portar nuestra aplicación de un marco a otro de esta manera.
Qué queremos: nos gustaría una “envoltura” que proporcione lo mismo interfaz consistente al módulo supra – y haga esto para cada módulo de nivel inferior (o infra módulo).
Aquí hay un ejemplo sencillo variado:
var infra1 = (function()
function alertMessage(message)
alert(message);
return
notify: alertMessage
;
)();
var infra2 = (function()
function logMessage(message)
console.log(message);
return
notify: logMessage
;
)();
var Supra = function(writer)
var notifier = writer;
function writeMessage(msg)
notifier.notify(msg);
this.writeNotification = writeMessage;
;
var supra;
supra = new Supra(infra1);
supra.writeNotification('This is a message');
supra = new Supra(infra2);
supra.writeNotification('This is a message');
Tenga en cuenta que no importa qué tipo de módulo de nivel inferior “escribir” usemos (en este caso infra1
y infra2
), no tenemos que reescribir ninguna de las implementaciones de nuestro módulo de alto nivel, Supra
. Esto se debe a que DIP aprovecha dos principios de diseño de software diferentes: “IoC” (inversión de control) y “DI” (inyección de dependencia).
La mejor analogía con la que me he encontrado es la imagen que se muestra a continuación.
Toda fuente eléctrica se basa en un interfaz específico para los tipos de cosas que necesitan conectarse.
Descripción de jQuery:
Este patrón se puede aplicar fácilmente al uso de marcos como jQuery. Un ejemplo sería el simple identificador DOM-Query. Podemos usar DIP para permitir el acoplamiento flexible de modo que si alguna vez decidimos cambiar de marco o confiar en los métodos nativos de consulta DOM, el mantenimiento sea fácil:
var jQ = (function($)
return
getElement: $
;
)(jQuery);
var nativeModule = (function()
return
getElement: document.querySelector
;
)();
var SupraDOMQuery = function(api)
var helper = api, thus = this;
function queryDOM(selector)
el = helper.getElement(selector);
return thus;
this.get = queryDOM;
;
var DOM;
DOM = new SupraDOMQuery(jQ);
DOM.get('#id.class');
DOM = new SupraDOMQuery(nativeModule);
DOM.get('#id.class');
Obviamente, este ejemplo necesitaría magnitudes de más funcionalidad para ser práctico, pero espero que se entienda.
Básicamente, las diferencias entre un Adaptador y una Fachada se vuelven algo triviales. En una fachada, probablemente esté viendo un solo módulo que envuelve una API u otro módulo; mientras que un adaptador crea una API de fachada coherente para cada uno de sus módulos y explota esta técnica para evitar el acoplamiento estrecho.
La mayoría de los libros de patrones de diseño de JavaScript tratan sobre el patrón de adaptador; uno que pasa específicamente por un ‘adaptador jQuery’ es Aprendizaje de patrones de diseño de JavaScript por Addy Osmani publicado por O’Reilly — aquí. Sin embargo, también recomiendo investigar Patrones de diseño de JavaScript profesional por Dustin Diaz y Ross Harmes publicado por Presionar — Echale un vistazo. Sin embargo, creo que es importante comprender el contexto en el que planeamos implementar DIP en relación con jQuery.
Espero que esto ayude a aclarar las cosas 🙂
Si entiendes que te ha sido de provecho este artículo, sería de mucha ayuda si lo compartieras con más programadores de esta forma contrubuyes a dar difusión a este contenido.