JavaScript dependency inversion principle

Can anyone help illustrate the principle of dependency inversion in jQuery JavaScript?

To highlight and explain these 2 points:

but. High-level modules should not be dependent on low-level modules. Both should depend on abstractions.

B. Abstractions should not depend on details. Details should depend on abstractions.

What are abstractions or high / low modules?

It really helps in my understanding, thanks!

+7
source share
4 answers

I would say that DIP is used in JavaScript the same way as in most programming languages, but you should be aware of the role of duck typing. Let me make an example to understand what I mean ...

Say I want to contact the server for some data. Without DIP, this might look like this:

$.get("/address/to/data", function (data) { $("#thingy1").text(data.property1); $("#thingy2").text(data.property2); }); 

With DIP, I can write code instead, for example

 fillFromServer("/address/to/data", thingyView); 

where the abstraction fillFromServer can for a particular case when we want to use jQuery Ajax will be implemented as

 function fillFromServer(url, view) { $.get(url, function (data) { view.setValues(data); }); } 

and the abstraction view can be implemented for a specific case of a presentation based on elements with identifiers thingy1 and thingy2 as

 var thingyView = { setValues: function (data) { $("#thingy1").text(data.property1); $("#thingy2").text(data.property2); } }; 

Principle A:

  • fillFromServer belongs to a low-level module, treating it as a low-level interaction between the server and the view. Something like, say, the settingsUpdater object will be part of a higher-level module, and it will rely on fillFromServer abstractions --- not on the details of it, which in this case are implemented through jQuery.
  • Likewise, fillFromServer is independent of the features of the DOM elements and their identifiers to do their job; instead, it depends on the abstraction of a view , which for its purposes is any type that has the setValues method. (This is what is meant by a duck set.)

Principle B:

This is slightly less easy to see in JavaScript with its duck type; in particular, something like view does not follow from (i.e. depends on) a kind of type viewInterface . But we can say that our particular instance of thingyView is a part that "depends" on the view abstraction.

Actually, this ā€œdependsā€ on the fact that the callers understand what methods should be called, that is, the callers are aware of the corresponding abstraction. In ordinary object-oriented languages, it is easier to see the dependency of thingyView explicitly on the abstraction itself. In such languages, the abstraction will be implemented in the interface (say, IView in C # or Viewable in Java), and the explicit dependency will be implemented through inheritance ( class ThingyView : IView or class ThingyView implements Viewable ). However, the same feelings apply.


Why is that cool? Well, let's say, once I needed to put server data in text fields with identifiers text1 and text2 instead of <span /> with identifiers thingy1 and thingy2 . In addition, let's say that this code was called very often, and benchmarking showed that critical performance is lost using jQuery. Then I could just create a new ā€œimplementationā€ of the view abstraction, for example:

 var textViewNoJQuery = { setValues: function (data) { document.getElementById("text1").value = data.property1; document.getElementById("text2").value = data.property2; } }; 

Then I insert this specific example of a view abstraction into my fillFromServer abstraction:

 fillFromServer("/address/to/data", textViewNoJQuery); 

This did not require changes to the fillFromServer code, because it depended only on the abstraction of the view using the setValues method, and not on the details of the DOM and how we access it. Not only does it satisfy us that we can reuse the code, it also indicates that we have cleanly separated our problems and created very future code.

+25
source

EDIT:

This shows the use of DIP in raw JavaScript and a less complete jQuery example. However, the following description can be easily applied to jQuery. See the jQuery example below.

The best way is to use the ā€œAdapter Patternā€ - also called the ā€œwrapperā€.

An adapter is basically a way to wrap an object or module so that it provides its dependents with the same consistent interface . Thus, a dependent class (usually a higher-level class ) can easily replace modules of the same type.

An example of this is a high-level module (or higher), which depends on Geo / Mapping modules.

Let's analyze this. If our supra module already uses GoogleMaps, but then the manual decides that it is cheaper to go with LeafletMaps, we don’t want to rewrite every method call from gMap.showMap(user, latLong) to leaflet.render(apiSecret,latLong, user) , etc. d. It would be a nightmare to port our application from one framework to another.

What we need: we need a "wrapper" that provides the same consistent interface for the supra module - and does this for each lower-level module (or infra-module).

Here is a simple example:

 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'); 

Please note that no matter what type of lower-level module we write (in this case infra1 and infra2 ), we do not need to rewrite any implementation of our high-level module, Supra . This is because DIP uses two different principles of software development: ā€œIoCā€ (control inversion) and ā€œDIā€ (dependency injection).

The best analogy I've come across is the image shown below.

enter image description here Each electrical source relies on an interface specific to the types of things that need to be connected to it.

jQuery Description:

This template can be easily applied to the use of frameworks such as jQuery. One example would be a simple DOM-Query descriptor. We can use DIP to allow loose communication so that if we ever decide to switch frameworks or rely on our own DOM-Query methods, maintenance is easy:

 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'); 

Obviously this example will require more functionality to be practical, but I hope this makes sense.

In principle, the differences between the adapter and the facade become somewhat trivial. In Facade, you are probably looking at one module that wraps an API or another module; while the adapter creates a consistent Facade API for each of its modules and uses this technique to eliminate hard communication.

Most books on JavaScript design patterns follow the adapter pattern; one that specifically translates the "jQuery Adapter" is learning the JavaScript design patterns from Addy Osmani published by O'Reilly here . However, I also advise looking at the design patterns of JavaScript by Dustin Diaz and Ross Harms, published by Apress - check it out . However, I think it is important to understand the context in which we plan to implement DIP with respect to jQuery.

Hope this helps clarify the situation :)

+4
source

Useful illustrations found here .

+2
source

Dependency Inversion Principle in jQuery JavaScript

There is no connection between DI and jQuery. DI is all about structure and assembly application from compoents. jQuery is a convenient wrapper around the DOM, no more, it does not have any structure or components.

You can use DI to build your JavaScript application, but it will look the same whether you use jQuery or not.

0
source

All Articles