Вопрос

Кто-нибудь может помочь проиллюстрировать Принцип инверсии зависимостей в JavaScript jQuery?

Который выделил бы и объяснил бы эти 2 момента:

A.Модули высокого уровня не должны зависеть от модулей низкого уровня.И то, и другое должно зависеть от абстракций.

B.Абстракции не должны зависеть от деталей.Детали должны зависеть от абстракций.

Что такое абстракции или модули высокого / низкого уровня?

Это действительно поможет в моем понимании, спасибо!

Это было полезно?

Решение

Я бы сказал, что DIP применяется в JavaScript почти так же, как и в большинстве языков программирования, но вы должны знать о роли duck typing .Давайте приведем пример, чтобы понять, что я имею в виду...

Допустим, я хочу связаться с сервером для получения некоторых данных.Без применения DIP это может выглядеть как:

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

С помощью DIP я мог бы вместо этого написать код типа

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

где абстракция fillFromServer может для конкретного случая, когда мы хотим использовать Ajax от jQuery быть реализованным как

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

и абстракция view может быть реализован для конкретного случая представления, основанного на элементах с идентификаторами thingy1 и thingy2 как

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

Принцип А:

  • fillFromServer принадлежит низкоуровневому модулю, обрабатывающему таким образом низкоуровневое взаимодействие между сервером и представлением.Что-то вроде, скажем, a settingsUpdater объект был бы частью модуля более высокого уровня, и он полагался бы на fillFromServer абстракция --- не на ее деталях, которые в данном случае реализованы с помощью jQuery.
  • Аналогично, fillFromServer не зависит от специфики элементов DOM и их идентификаторов для выполнения своей работы;вместо этого это зависит от абстракции view, который для своих целей представляет собой любой тип , имеющий setValues способ.(Это то, что подразумевается под "утиным набором текста".)

Принцип В:

Это немного менее легко увидеть в JavaScript с его утиным набором текста;в частности, что-то вроде view не является производным от (т.е.зависеть от) какого-то viewInterface Тип.Но мы можем сказать, что наш конкретный пример, thingyView, является деталь это "зависит" от абстракции view.

Реально, это "зависит" от того факта, что вызывающие понимают, какие методы должны быть вызваны, т. е.что звонящие - это осознающий соответствующей абстракции.В обычных объектно-ориентированных языках легче увидеть зависимость thingyView явно на самой абстракции.В таких языках абстракция была бы воплощена в интерфейсе (скажем, IView в C # или Viewable в Java), а явная зависимость осуществляется через наследование (class ThingyView : IView или class ThingyView implements Viewable).Однако здесь применимо то же самое чувство.


Почему это круто?Ну, допустим, однажды мне нужно было поместить данные сервера в текстовые поля с идентификаторами text1 и text2 вместо того , чтобы <span />ы с идентификаторами thingy1 и thingy2.Более того, предположим, что этот код вызывался очень-очень часто, и сравнительный анализ показал, что критическая производительность терялась из-за использования jQuery.Затем я мог бы просто создать новую "реализацию" view абстракция, вот так:

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

Затем я вводю этот конкретный экземпляр абстракции представления в свой fillFromServer абстракция:

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

Это требовало НЕТ изменения в fillFromServer код, потому что это зависело только от абстракции view с помощью setValues метод, а не о деталях DOM и о том, как мы получаем к нему доступ.Это не только удовлетворяет тем, что мы можем повторно использовать код, это также указывает на то, что мы четко разделили наши проблемы и создали очень перспективный код.

Другие советы

Редактировать:

Это показывает использование DIP в необработанном JavaScript и менее полный Пример jQuery.Однако следующее описание может быть легко применено к jQuery.Смотрите пример jQuery внизу.

Лучший способ - воспользоваться преимуществами "Шаблона адаптера", также называемого "оболочкой".

Адаптер - это, по сути, способ упаковки объекта или модуля таким образом, чтобы он обеспечивал то же самое согласованный интерфейс к его иждивенцы.Таким образом, зависимый класс (обычно a более высокий уровень class) может легко заменять модули одного и того же типа.

Примером этого может быть высокоуровневый (или выше) модуль, который зависит от модулей Гео /Картографии.

Давайте проанализируем это.Если наш модуль supra уже использует GoogleMaps, но затем руководство решает, что дешевле использовать LeafletMaps - мы не хотим переписывать каждый вызов метода из gMap.showMap(user, latLong) Для leaflet.render(apiSecret,latLong, user), et al.Это был бы кошмар, если бы пришлось таким образом переносить наше приложение с одной платформы на другую.

Чего мы хотим:Мы хотели бы иметь "оболочку", которая обеспечивает то же самое согласованный интерфейс к модулю supra - и делайте это для каждого модуль более низкого уровня (или infra модуль).

Вот очень простой пример:

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

Обратите внимание, что независимо от того, какой тип модуля нижнего уровня "write" мы используем (в данном случае infra1 и infra2), нам не нужно переписывать какую-либо реализацию нашего высокоуровневого модуля, Supra.Это связано с тем, что DIP использует преимущества двух различных принципов проектирования программного обеспечения:"IoC" (Инверсия управления) и "DI" (Внедрение зависимости).

Лучшая аналогия, с которой я столкнулся, - это картинка, показанная ниже.

enter image description here Каждый источник электроэнергии зависит от интерфейс специфичный для тех типов вещей, которые необходимо к нему подключить.

Описание jQuery:

Этот шаблон может быть легко применен к использованию фреймворков, таких как jQuery.Одним из примеров может быть простой дескриптор DOM-запроса.Мы можем использовать DIP для обеспечения свободной связи, чтобы, если мы когда-нибудь решим сменить фреймворки или будем полагаться на собственные методы DOM-запросов, обслуживание было простым:

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

Очевидно, что для того, чтобы этот пример был практичным, потребовалось бы гораздо больше функциональности, но я надеюсь, что он передает суть дела.

В принципе, различия между Адаптером и Фасадом становятся несколько тривиальными.На фасаде вы, вероятно, смотрите на один модуль, который обертывает API или другой модуль;принимая во внимание, что Адаптер создает согласованный фасадный API для каждого из своих модулей и использует этот метод для устранения тесной связи.

Большинство книг по шаблонам проектирования JavaScript посвящены шаблону адаптера;тот, который специально используется через "Адаптер jQuery", - это Изучение шаблонов проектирования JavaScript Автор: Адди Османи опубликовано О'Рейли -- здесь.Тем не менее, я также советую изучить Профессиональные шаблоны проектирования JavaScript Автор: Дастин Диас и Росс Хармс опубликовано Апресс -- зацени это.Тем не менее, я думаю, что важно понимать контекст, в котором мы планируем реализовать DIP применительно к jQuery.

Я надеюсь, что это поможет кое-что прояснить :)

Нашел несколько полезных иллюстраций здесь.

Принцип инверсии зависимостей в JavaScript jQuery

Нет никакой связи между DI и jQuery.DI - это все о структуре и сборке приложения из компонентов.jQuery - это удобная оболочка вокруг DOM, не более того, у него нет какой-либо структуры или компонентов.

Вы можете использовать DI для сборки вашего приложения на JavaScript, но это будет выглядеть практически одинаково, независимо от того, используете вы jQuery или нет.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top