Принцип инверсии зависимостей в JavaScript - PullRequest
7 голосов
/ 18 марта 2011

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

Что бы выделить и объяснить эти 2 пункта:

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

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

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

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

Ответы [ 4 ]

27 голосов
/ 18 марта 2011

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

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

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

При использовании DIP я мог бы вместо этого написать код, например

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

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

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

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

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

Принцип A:

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

Принцип B:

Это немного менее легко увидеть в 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 и какмы получаем к нему доступ.Это не только удовлетворяет нас тем, что мы можем повторно использовать код, но и указывает, что мы четко разделили наши проблемы и создали очень перспективный код.

6 голосов
/ 17 апреля 2014

РЕДАКТИРОВАТЬ:

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

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

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

Примером этого может быть высокий уровень (или * 1019).* supra ) модуль, который зависит от модулей Geo / Mapping.

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

Что мы хотим: нам нужна «оболочка», которая обеспечивает такой же постоянный интерфейс длямодуль выше - и делайте это для каждого модуля нижнего уровня (или инфра модуля).

Вот простой пример:

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

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

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

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

jQuery Описание:

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

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-интерфейс Facade для каждого из своих модулей и использует эту технику, чтобы устранить тесную связь.

Большинство книг JavaScript Design Patterns идут поверх Pattern Adapter;один из них, который более подробно описывает «jQuery Adapter», - это Изучение шаблонов проектирования JavaScript от Addy Osmani , опубликованное O'Reilly - здесь ,Однако я также советую изучить Pro JavaScript Design Patterns от Дастина Диаса и Росса Хармса , опубликованных Apress - , проверить .Тем не менее, я считаю важным понять контекст, в котором мы планируем реализовать DIP по отношению к jQuery.

Надеюсь, это поможет прояснить ситуацию:)

2 голосов
/ 18 марта 2011

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

0 голосов
/ 22 ноября 2011

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...