Предисловие
В этой главе мы собираемся объяснить пятую главу реализации пяти основных принципов солидного языка JavaScript, который является LSP (принцип инверсии зависимости).
Оригинальный английский текст: http://freshbrewedcode.com/derekgreeer/2012/01/22/solid-javascript-the-preadency-inversion-principle/
Принцип инверсии опоры
Описание принципа инверсии зависимости:
A. Модули высокого уровня не должны зависеть от низкоуровневых модулей. Оба должны зависеть от абстракций.
Модули высокого уровня не должны зависеть от модулей низкого уровня, оба должны полагаться на абстракцию
Б. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Аннотация не должна зависеть от деталей, детали должны зависеть от абстракции
Наиболее важным вопросом с принципом инверсии зависимости является обеспечение того, чтобы основные компоненты приложения или структуры были отделены от деталей реализации невозможных базовых компонентов, что гарантирует, что на наиболее важные части программы не влияют изменения и модификации низкоуровневых компонентов.
Первая часть этого принципа заключается в связи между модулями высокого уровня и модулями низкого уровня. В традиционной архитектуре дивизии модули высокого уровня (инкапсулируют основную бизнес-логику программы) всегда полагаются на некоторые низкоуровневые модули (некоторые основные точки). Когда применяется принцип инверсии зависимости, отношения изменяются. В отличие от модулей высокого уровня, которые полагаются на низкоуровневые модули, инверсия зависимости заставляет модули низкого уровня полагаются на интерфейсы, определенные в модулях высокого уровня. Например, если вы хотите сохранить данные для программы, традиционный дизайн заключается в том, что основной модуль зависит от API постоянного модуля. После реконструкции в соответствии с принципом инверсии зависимости, модуль Core должен определить постоянный интерфейс API, а затем экземпляр постоянной реализации должен реализовать интерфейс API, определенный модулем Core.
Вторая часть этого принципа описывает правильную связь между абстракцией и деталями. Понимание этой части более полезно, понимая язык C ++, потому что ее применимость более очевидна.
В отличие от некоторых статически напечатанных языков, C ++ не предоставляет концепцию уровня языка для определения интерфейсов. Какова взаимосвязь между определением класса и реализацией класса? В C ++ классы определяются в форме файлов заголовков, которые определяют методы и переменные члена класса, которые необходимо реализовать исходный файл. Поскольку все переменные и частные методы определены в файле заголовка, их можно использовать для абстрагирования и отделки их перед деталями реализации. Концепция интерфейса реализована путем определения только абстрактных методов (абстрактный базовый класс в C ++) используется для реализации классов.
DIP и JavaScript
Поскольку JavaScript - это динамичный язык, нет необходимости абстрагировать для развязки. Поэтому абстракция не должна полагаться на детали. Это изменение не оказывает большого влияния на JavaScript, но модули высокого уровня не должны полагаться на модули низкого уровня, но оказывают большое влияние.
При обсуждении принципа инверсии зависимости в контексте статически напечатанных языков, концепции связи включают семантическую и физическую. Это означает, что если модуль высокого уровня зависит от модуля низкого уровня, он не только объединяет семантический интерфейс, но и физический интерфейс, определяемый в базовом модуле. Другими словами, модули высокого уровня должны быть отделены не только от сторонней библиотеки, но и от местных модулей низкого уровня.
Чтобы объяснить это, представьте, что программа .NET может содержать очень полезный модуль высокого уровня, который опирается на постоянный модуль низкого уровня. Когда автор должен добавить аналогичный интерфейс к API постоянств, независимо от того, используется ли принцип инверсии зависимости или нет, модули высокого уровня не могут быть использованы в других программах, прежде чем переосмыслить новый интерфейс этого низкоуровневого модуля.
В JavaScript применимость принципа инверсии зависимости ограничена семантической связью между модулями высокого уровня и модулями низкого уровня. Например, DIP может добавлять интерфейсы по мере необходимости вместо соединения неявных интерфейсов, определяемых модулями низкого уровня.
Чтобы понять это, давайте посмотрим на следующий пример:
Кода -копия выглядит следующим образом:
$ .fn.trackmap = function (options) {
var defaults = {
/ * по умолчанию */
};
options = $.
var mapoptions = {
Центр: новый google.maps.latlng (options.latity, options.longity),
Увеличение: 12,
Maptypeid: Google.maps.maptypeid.roadmap
},
map = new Google.maps.map (this [0], mapoptions),
pos = new Google.maps.latlng (options.latity, options.longity);
var marker = new Google.maps.marker ({
позиция: pos,
Название: Options.title,
Значок: Options.icon
});
marker.setmap (map);
options.feed.update (function (Latitude, Longitude) {
marker.setMap (null);
var newlatlng = new Google.maps.latlng (широта, долгота);
marker.position = newlatlng;
marker.setmap (map);
map.setCenter (newlatlng);
});
вернуть это;
};
var Updater = (function () {
// частные свойства
возвращаться {
Обновление: function (обратный вызов) {
UpdateMap = обратный вызов;
}
};
}) ();
$ ("#map_canvas"). Trackmap ({
Широта: 35,044640193770725,
Долгота: -89,98193264007568,
ИКОН: 'http://bit.ly/zjngde',
Название: «Номер отслеживания: 12345»,
Feed: Updater
});
В приведенном выше коде существует небольшая библиотека классов JS, которая преобразует DIV в карту для отображения в настоящее время отслеживаемой информации о месте. Функция TrackMap имеет 2 зависимости: сторонний API Google Maps и канал местоположения. Ответственность объекта Feed состоит в том, чтобы вызвать обратный вызов (предоставленный при инициализации), когда позиция значка обновляется, и пройти в широте широте и долготе. API Google Maps используется для рендеринга интерфейсов.
Интерфейс объекта Feed может быть основан на установке или не разработан в соответствии с требованиями функции TrackMap установки. На самом деле, его роль очень проста, сосредотачиваясь на простых различных реализациях и не нужно так сильно полагаться на карты Google. Семантика трек -карты связана с API Google Maps. Если вам нужно переключиться на разные поставщики карт, вы должны переписать функцию TrackMap, чтобы она могла адаптироваться к разным поставщикам.
Чтобы перевернуть семантическую связь библиотеки классов Google Maps, нам необходимо переписать функцию Design Trackmap, чтобы семантическое соединение неявного интерфейса (абстрактный интерфейс поставщика поставщика карт). Нам также нужен объект реализации, который адаптирован к API Google Maps. Ниже приведено рефакторированная функция трека:
Кода -копия выглядит следующим образом:
$ .fn.trackmap = function (options) {
var defaults = {
/ * по умолчанию */
};
options = $.
options.provider.showmap (
это [0],
Options.latity,
Options.longity,
Options.icon,
Options.title);
options.feed.update (function (Latitude, Longitude) {
options.provider.updatemap (широта, долгота);
});
вернуть это;
};
$ ("#map_canvas"). Trackmap ({
Широта: 35,044640193770725,
Долгота: -89,98193264007568,
ИКОН: 'http://bit.ly/zjngde',
Название: «Номер отслеживания: 12345»,
Feed: Updater,
Поставщик: TrackMap.googlemapsProvider
});
В этой версии мы перепроектировали функцию TrackMap и необходимый интерфейс поставщика карт, а затем перенесли детали реализации в отдельный компонент GooglemapsProvider, который может быть независимо инкапсулирован в отдельный модуль JavaScript. Вот моя реализация GooglemapsProvider:
Кода -копия выглядит следующим образом:
TrackMap.googlemapsprovider = (function () {
Var Marker, Map;
возвращаться {
ShowMap: Function (элемент, широта, долгота, значок, заголовок) {
var mapoptions = {
Центр: New Google.maps.latlng (широта, долгота),
Увеличение: 12,
Maptypeid: Google.maps.maptypeid.roadmap
},
pos = new Google.maps.latlng (широта, долгота);
map = new Google.maps.map (element, mapoptions);
marker = new Google.maps.marker ({
позиция: pos,
Название: Название,
Значок: значок
});
marker.setmap (map);
},
UpdateMap: function (широта, долгота) {
marker.setMap (null);
var newlatlng = new Google.maps.latlng (широта, долгота);
marker.position = newlatlng;
marker.setmap (map);
map.setCenter (newlatlng);
}
};
}) ();
После внесения вышеупомянутых изменений функция TrackMap станет очень гибкой и не должна полагаться на API Google Maps. Вместо этого другие поставщики карт могут быть заменены по желанию, то есть любой поставщик карт может быть адаптирован в соответствии с потребностями программы.
Когда инъекция зависимостей?
Это немного не связано. Фактически, концепция инъекции зависимости часто смешивается с принципом инверсии зависимости. Чтобы прояснить эту разницу, необходимо объяснить:
Инъекция зависимости является особой формой контрольной инверсии, а инверсия означает, как компонент приобретает свои зависимости. Средние значения инъекции зависимости: зависимость предоставляется компоненту, а не для компонента для получения зависимости, что означает создание экземпляра зависимости, запрашивая зависимость через фабрику и запрашивая зависимость через локатор сервиса или сам компонент. Принцип инверсии зависимости и инъекция зависимости сосредоточены на зависимостях и используются для инверсии. Тем не менее, принцип инверсии зависимости не фокусируется не на том, как компоненты приобретают зависимости, а только на том, как модули высокого уровня отделены от модулей низкого уровня. В некотором смысле принцип инверсии зависимости является еще одной формой контрольной инверсии. Здесь инверсия - какой модуль определяет интерфейс (определяется от более низкого уровня, инверсию до более высокого уровня).
Суммировать
Это последняя статья из пяти основных принципов. В этих 5 статьях мы видим, насколько солидно реализовано в JavaScript. Различные принципы объясняются под разными углами в JavaScript. (Дядя Примечание. На самом деле, я думаю, что, хотя это немного неуместно, с другой точки зрения, общие принципы на самом деле одинаковы на различных языках.)