Vorwort
In diesem Kapitel werden wir das fünfte Kapitel der Umsetzung der fünf Hauptprinzipien der soliden JavaScript -Sprache erläutern, der LSP (das Abhängigkeitsinversionsprinzip).
Original Englisch Text: http://freshbrewedcode.com/derekgreeer/2012/01/22/solid-javascript-thependency-inversion-principle/
Reliance Inversion Prinzip
Die Beschreibung des Prinzips der Abhängigkeitsinversion lautet:
A. hochrangige Module sollten nicht von Modulen mit niedrigem Niveau abhängen. Beide sollten von Abstraktionen abhängen.
Auf hohen Modulen sollten nicht von Modulen auf niedrigem Niveau abhängen, beide sollten auf eine Abstraktion beruhen
B. Abstraktionen sollten nicht von Details abhängen. Details sollten von Abstraktionen abhängen.
Abstract sollte nicht von Details abhängen. Details sollten von der Abstraktion abhängen
Das wichtigste Problem mit dem Prinzip der Abhängigkeitsinversion besteht darin, sicherzustellen, dass die Hauptkomponenten des Anwendung oder des Frameworks aus den Implementierungsdetails der nicht wichtigen zugrunde liegenden Komponenten entkoppelt sind, wodurch sichergestellt wird, dass die wichtigsten Teile des Programms nicht von Änderungen und Änderungen der Komponenten mit niedriger Ebene betroffen sind.
Der erste Teil dieses Prinzips betrifft die Kopplung zwischen hochrangigen Modulen und Modulen auf niedriger Ebene. In der traditionellen Division Architecture beruhen hochrangige Module (die die Kerngeschäftslogik des Programms zusammenfassen) immer auf einige Module auf niedriger Ebene (einige grundlegende Punkte). Wenn das Prinzip der Abhängigkeitsinversion angewendet wird, wird die Beziehung umgekehrt. Im Gegensatz zu hochrangigen Modulen, die auf Modulen mit niedrigem Niveau angewiesen sind, stützt sich die Abhängigkeitsinversion auf niedrig Ebenen auf Schnittstellen, die in Modulen auf hoher Ebene definiert sind. Wenn Sie beispielsweise Daten für ein Programm bestehen möchten, ist das traditionelle Design, dass das Kernmodul von der API eines anhaltenden Moduls abhängt. Nach dem Wiederaufbau nach dem Prinzip der Abhängigkeitsinversion muss das Kernmodul eine persistente API -Schnittstelle definieren, und dann muss die persistente Implementierungsinstanz die vom Kernmodul definierte API -Schnittstelle implementieren.
Der zweite Teil dieses Prinzips beschreibt die korrekte Beziehung zwischen Abstraktion und Detail. Das Verständnis dieses Teils ist hilfreicher, indem sie die C ++ - Sprache verstehen, da seine Anwendbarkeit offensichtlicher ist.
Im Gegensatz zu einigen statisch typisierten Sprachen bietet C ++ kein Konzept auf Sprachebene, um Schnittstellen zu definieren. Wie ist die Beziehung zwischen Klassendefinition und Klassenimplementierung? In C ++ werden Klassen in Form von Header -Dateien definiert, die die Klassenmitgliedmethoden und Variablen definieren, die die Quelldatei implementieren muss. Da alle Variablen und privaten Methoden in der Header -Datei definiert sind, können sie verwendet werden, um sie vor der Implementierungsdetails abzubauen und zu entkoppeln. Das Konzept der Schnittstelle wird durch Definieren von abstrakten Methoden (die abstrakte Basisklasse in C ++) implementiert, um Klassen zu implementieren.
Dip und JavaScript
Da JavaScript eine dynamische Sprache ist, besteht keine Notwendigkeit, für die Entkopplung abstrahiert zu werden. Daher sollte die Abstraktion nicht auf Details beruhen. Diese Änderung hat keinen großen Einfluss auf JavaScript, aber hochrangige Module sollten sich nicht auf Module auf niedriger Ebene verlassen, sondern einen großen Einfluss haben.
Bei der Erörterung des Prinzips der Abhängigkeitsinversion im Kontext statisch typisierter Sprachen umfassen die Konzepte der Kopplung semantisch und physisch. Dies bedeutet, dass ein hochrangiges Modul von einem Modul mit niedrigem Niveau abhängt, es nicht nur die semantische Schnittstelle, sondern auch die im zugrunde liegende Modul definierte physikalische Schnittstelle. Mit anderen Worten, hochrangige Module müssen nicht nur aus der Bibliothek von Drittanbietern, sondern auch aus nativen Modulen mit niedrigem Niveau entkoppelt werden.
Stellen Sie sich vor, dass ein .NET-Programm möglicherweise ein sehr nützliches Modul auf hoher Ebene enthält, das auf einem anhaltenden Modul auf niedrigem Niveau beruht. Wenn der Autor der Persistenz-API eine ähnliche Schnittstelle hinzufügen muss, unabhängig davon, ob das Abhängigkeitsinversionsprinzip verwendet wird oder nicht, können Module auf hoher Ebene nicht in anderen Programmen wiederverwendet werden, bevor die neue Schnittstelle dieses Moduls auf niedriger Ebene neu implementiert wird.
In JavaScript beschränkt sich die Anwendbarkeit des Prinzips der Abhängigkeitsinversion auf die semantische Kopplung zwischen Modulen auf hoher Ebene und Modulen auf niedriger Ebene. Beispielsweise kann ein DIP-Schnittstellen nach Bedarf anstelle von impliziten Schnittstellen hinzufügen, die durch Module auf niedriger Ebene definiert sind.
Um dies zu verstehen, werfen wir einen Blick auf das folgende Beispiel:
Die Codekopie lautet wie folgt:
$ .fn.trackmap = Funktion (Optionen) {
var defaults = {
/ * Standardeinstellungen */
};
options = $ .extend ({}, Standardeinstellungen, Optionen);
var mapOptions = {
Mitte: New Google.maps.latlng (options.latitude, options.longitude),
Zoom: 12,
MAPTYPEID: google.maps.maptypeid.roadmap
},
map = new Google.maps.map (this [0], mapOptions),
pos = new Google.maps.latlng (options.latitude, options.longitude);
var marker = new Google.maps.marker ({{
Position: pos,
Titel: Optionen.Title,
Icon: options.icon
});
marker.setMap (map);
options.feed.update (Funktion (Breitengrad, Länge) {
marker.setMap (null);
var newlatlng = new Google.maps.latlng (Breitengrad, Längengrad);
marker.position = newlatlng;
marker.setMap (map);
map.setCenter (newlatlng);
});
gib dies zurück;
};
var updater = (function () {
// Private Eigenschaften
zurückkehren {
Update: Funktion (Rückruf) {
updatemap = callback;
}
};
}) ();
$ ("#map_canvas"). TrackMap ({{{
Breitengrad: 35.044640193770725,
Länge: -89.98193264007568,
Icon: 'http://bit.ly/zjngde', ',
Titel: 'Tracking -Nummer: 12345',
Feed: Updater
});
Im obigen Code gibt es eine kleine JS -Klassenbibliothek, die eine DIV in eine Karte umwandelt, um die aktuell verfolgten Standortinformationen anzuzeigen. Die TrackMap-Funktion hat 2 Abhängigkeiten: die Google Maps-API von Drittanbietern und den Standort-Feed. Die Verantwortung des Feed -Objekts besteht darin, einen Rückruf zurückzurufen (bei der Initialisierung), wenn die Icon -Position aktualisiert und in den Breitengrad- und Präzisions -Längengrad bestanden wird. Die Google Maps -API wird zum Rendern von Schnittstellen verwendet.
Die Schnittstelle des Futtermittelobjekts kann auf der Installation basieren oder nicht gemäß den Anforderungen der Installations -Trackmap -Funktion ausgelegt. Tatsächlich ist seine Rolle sehr einfach und konzentriert sich auf einfache unterschiedliche Implementierungen und muss nicht so sehr auf Google Maps angewiesen sein. Die Trackmap -Semantik ist an die Google Maps -API gekoppelt. Wenn Sie zu verschiedenen Kartenanbietern wechseln müssen, müssen Sie die TrackMap -Funktion umschreiben, damit sie sich an verschiedene Anbieter anpassen kann.
Um die semantische Kopplung der Google Maps -Klassenbibliothek umzudrehen, müssen wir die Design -Trackmap -Funktion in der semantischen Kopplung einer impliziten Schnittstelle umschreiben (Zusammenfassung der Schnittstelle des Kartenanbieters). Wir benötigen auch ein Implementierungsobjekt, das an die Google Maps -API angepasst ist. Das Folgende ist die refaktorierte Trackmap -Funktion:
Die Codekopie lautet wie folgt:
$ .fn.trackmap = Funktion (Optionen) {
var defaults = {
/ * Standardeinstellungen */
};
options = $ .extend ({}, Standardeinstellungen, Optionen);
options.provider.showmap (
Dies [0],
Optionen.Latitude,
Optionen.Longitude,
Optionen.ICON,
Optionen.titel);
options.feed.update (Funktion (Breitengrad, Länge) {
Optionen.Provider.Updatemap (Breitengrad, Längengrad);
});
gib dies zurück;
};
$ ("#map_canvas"). TrackMap ({{{
Breitengrad: 35.044640193770725,
Länge: -89.98193264007568,
Icon: 'http://bit.ly/zjngde', ',
Titel: 'Tracking -Nummer: 12345',
Feed: Updater,
Anbieter: TrackMap.googlemapsProvider
});
In dieser Version haben wir die TRACKMAP -Funktion und die erforderliche Kartenanbieter -Schnittstelle neu gestaltet und die Implementierungsdetails dann in eine separate GooglemapsProvider -Komponente verschoben, die unabhängig in ein separates JavaScript -Modul eingekapselt werden kann. Hier ist meine Implementierung von GooglemapsProvider:
Die Codekopie lautet wie folgt:
TrackMap.googlemapsProvider = (function () {
var Marker, Karte;
zurückkehren {
Showmap: Funktion (Element, Breitengrad, Längengrad, Symbol, Titel) {
var mapOptions = {
Mitte: Neue Google.maps.latlng (Breitengrad, Längengrad),
Zoom: 12,
MAPTYPEID: google.maps.maptypeid.roadmap
},
pos = new Google.maps.latlng (Breitengrad, Längengrad);
map = new Google.maps.map (Element, MapOptions);
marker = new Google.maps.marker ({{
Position: pos,
Titel: Titel,
Symbol: Symbol
});
marker.setMap (map);
},
updatemap: function (latitude, longitude) {
marker.setMap (null);
var newlatlng = new Google.maps.latlng (Breitengrad, Längengrad);
marker.position = newlatlng;
marker.setMap (map);
map.setCenter (newlatlng);
}
};
}) ();
Nachdem die oben genannten Änderungen vorgenommen wurden, wird die TrackMap -Funktion sehr flexibel und muss sich nicht auf die Google Maps -API verlassen. Stattdessen können andere Kartenanbieter nach Belieben ersetzt werden, dh jeder Kartenanbieter kann entsprechend den Anforderungen des Programms angepasst werden.
Wann ist Abhängigkeitsinjektion?
Es ist etwas unabhängig. Tatsächlich wird das Konzept der Abhängigkeitsinjektion häufig mit dem Prinzip der Abhängigkeitsinversion gemischt. Um diesen Unterschied zu verdeutlichen, muss es erklären, zu erklären:
Die Abhängigkeitsinjektion ist eine spezielle Form der Kontrollinversion, und die Inversion bedeutet, wie eine Komponente ihre Abhängigkeiten erwirbt. Abhängigkeitsinjektionsmittel: Die Abhängigkeit wird der Komponente und nicht der Komponente zur Verfügung gestellt, um die Abhängigkeit zu erhalten, was bedeutet, eine Instanz der Abhängigkeit zu erstellen, die Abhängigkeit über die Fabrik zu beantragen und die Abhängigkeit über den Service -Locator oder die Komponente selbst zu fordern. Das Abhängigkeitsinversionsprinzip und die Abhängigkeitsinjektion konzentrieren sich beide auf Abhängigkeiten und werden zur Inversion verwendet. Das Prinzip der Abhängigkeitsinversion konzentriert sich jedoch nicht darauf, wie Komponenten Abhängigkeiten erwerben, sondern nur darauf, wie hochrangige Module von Modulen auf niedriger Ebene entkoppelt werden. In gewissem Sinne ist das Prinzip der Abhängigkeitsinversion eine andere Form der Kontrollinversion. Hier ist die Inversion, welches Modul die Schnittstelle definiert (definiert von der unteren Ebene, Inversion auf die höhere Ebene).
Zusammenfassen
Dies ist der letzte Artikel der fünf Hauptprinzipien. In diesen 5 Artikeln sehen wir, wie solide in JavaScript implementiert ist. Verschiedene Prinzipien werden aus verschiedenen Blickwinkeln im JavaScript erklärt. (Onkel Anmerkung: Tatsächlich denke ich, dass die allgemeinen Prinzipien aus einer anderen Perspektive in verschiedenen Sprachen tatsächlich gleich sind, obwohl es etwas unangemessen ist.)