搜尋
首頁web前端js教程深入理解JavaScript系列(22):S.O.L.I.D五大原則之依賴倒置原則DIP詳解_基礎知識

前言

本章我們要講解的是S.O.L.I.D五大原則JavaScript語言實作的第5篇,依賴倒置原則LSP(The Dependency Inversion Principle )。

英文原文:http://freshbrewedcode.com/derekgreer/2012/01/22/solid-javascript-the-dependency-inversion-principle/
依賴倒置原則

依賴倒置原則的描述是:

A. High-level modules should not depend on low-level modules.  Both should depend on abstractions.
   高層模組不應該依賴低層模組,二者都應該依賴抽象

B. Abstractions should not depend upon details.  Details should depend upon abstractions.
   抽像不應該依賴細節,細節應該依賴抽象
依賴倒置原則的最重要問題是確保應用程式或框架的主要元件從非重要的底層元件實現細節解耦出來,這將確保程式的最重要的部分不會因為低層次元件的變化修改而受影響。

這個原則的第一部分是關於高層模組和低層模組之間的耦合方式,在傳統的分成架構中,高層模組(封裝了程式的核心業務邏輯)總是依賴低層的一些模組(一些基礎點)。當應用依賴倒置原則的時候,關係就反過來了。和高層模組依賴低層模組不同,依賴倒置是讓低層模組依賴高層模組裡定義的介面。舉例來說,如果要給程式進行資料持久化,傳統的設計是核心模組依賴一個持久化模組的API,而根據依賴倒置原則重構以後,則是核心模組需要定義持久化的API接口,然後持久化的實作實例需要實作核心模組定義的這個API介面。

原則的第二部分描述的是抽象和細節之間的正確關係。理解這一部分,透過了解C 語言比較有幫助,因為他的適用性比較明顯。

不像一些靜態類型的語言,C 沒有提供一個語言級別的概念來定義接口,那類定義和類實現之間到底是怎麼樣的呢,在C 裡,類通過頭文件的形式來定義,其中定義了原始檔案需要實作的類別成員方法和變數。因為所有的變數和私有方法都定義在頭檔裡,所以可以用來抽象化以便和實作細節之前解耦出來。透過定只定義抽象方法來實作(C 裡是抽象基底類別)介面這個概念用來實作類別來實作。

DIP and JavaScript

因為JavaScript是動態語言,所以不需要去為了解耦而抽象化。所以抽像不應依賴細節這個改變在JavaScript裡沒有太大的影響,但高層模組不應該依賴低層模組卻有很大的影響。

在當靜態型別語言的脈絡裡討論依賴倒置原則的時候,耦合的概念包括語意(semantic)和物理(physical)兩種。這就是說,如果一個高層模組依賴於一個低層模組,也就是不僅耦合了語義接口,也耦合了在底層模組裡定義的物理接口。也就是說高層模組不只從第三方類別庫解耦出來,也需要從原生的低層模組解耦出來。

為了解釋這一點,想像一個.NET程式可能包含一個非常有用的高層模組,而這個模組依賴一個低層的持久化模組。當作者需要在持久化API裡增加一個類似的介面的時候,不管依賴倒置原則有沒有使用,高層模組在不重新實作這個低層模組的新介面之前是沒有辦法在其它的程式裡得到重用的。

在JavaScript裡,依賴倒置原則的適用性僅限於高層模組和低層模組之間的語意耦合,例如,DIP可以根據需要去增加介面而不是耦合低層模組定義的隱式介面。

為了來理解這個,我們看一下如下例子:

複製程式碼 程式碼如下:

$.fn.trackMap = 函數(選項) {
    var 預設值 = {
        /* 預設值 */
    };
    選項 = $.extend({}, 預設值, 選項);

    var mapOptions = {
        中心:新的 google.maps.LatLng(options.latitude,options.longitude),
        縮放:12,
        地圖類型 ID:google.maps.MapTypeId.ROADMAP
    },
        地圖 = new google.maps.Map(this[0], mapOptions),
        pos = new google.maps.LatLng(options.latitude,options.longitude);

    var mark = new google.maps.Marker({
        地點: pos,
        標題:選項.標題,
        圖示:選項.icon
    });

   marker.setMap(map);

    options.feed.update(function(緯度, 經度) {
        marker.setMap(null);
        var newLatLng = new google.maps.LatLng(緯度, 經度);
        標記.position = newLatLng;
        marker.setMap(地圖);
        map.setCenter(newLatLng);
    });

    回此;
};

var updater = (function() {
    // 私有屬性

    回 {
        更新:函數(回呼){
            updateMap = 回調;
        }
    };
})();

$("#map_canvas").trackMap({
    緯度: 35.044640193770725,
    經度:-89.98193264007568,
    圖示:'http://bit.ly/zjnGDe',
    title: '追蹤號碼:12345',
    摘要:更新器
});

在上述程式碼裡,一個小型的JS類別庫將一個DIV轉換成Map以便顯示目前追蹤的位置資訊。 trackMap函數有2個依賴:第三方的Google Maps API和Location feed。該feed物件的職責是當圖示位置更新的時候調用一個callback回呼(在初始化的時候提供的)並確定緯度緯度和精度經度。 Google Maps API是用來渲染介面的。

feed物件的介面可能遵循安裝,也可能沒有照裝trackMap函數的要求去設計,事實上,他的角色很簡單,形式在簡單的不同實現,不需要和Google Maps這麼依賴。採集上耦合了Google Maps API,如果需要切換不同的地圖那麼就必須對trackMap函數進行重構以便可以改裝不同的provider。

為了實現Google地圖類別庫的介面連接對接過來,我們需要重寫設計trackMap函數,以便對一個隱式介面(抽像出地圖式提供者的介面)進行介面連接,我們還需要一個介面連接Google Maps API的一個實作對象,如下是重構後的trackMap函數:

複製程式碼如下程式碼:

$.fn.trackMap = function(options) {
    var defaults = {
        /* defaults */
    };

    options = $.extend({}, defaults, options);

    options.provider.showMap(
        this[0],
        options.latitude,
        options.longitude,
        options.icon,
        options.title);

    options.feed.update(function(latitude, longitude) {
        options.provider.updateMap(latitude, longitude);
    });

    return this;
};

$("#map_canvas").trackMap({
    latitude: 35.044640193770725,
    longitude: -89.98193264007568,
    icon: 'http://bit.ly/zjnGDe',
    title: 'Tracking Number: 12345',
    feed: updater,
    provider: trackMap.googleMapsProvider
});


在該版本裡,我們重新設計了trackMap函數以及需要的一個地圖提供者接口,然後將實現的細節挪到了一個單獨的googleMapsProvider元件,該元件可能獨立封裝成一個單獨的JavaScript模組。如下是我的googleMapsProvider實作:
複製程式碼 程式碼如下:

trackMap.googleMapsProvider = (function() {
    var marker, map;

    return {
        showMap: function(element, latitude, longitude, icon, title) {
            var mapOptions = {
                center: new google.maps.LatLng(latitude, longitude),
                zoom: 12,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            },
                pos = new google.maps.LatLng(latitude, longitude);

            map = new google.maps.Map(element, mapOptions);

            marker = new google.maps.Marker({
                position: pos,
                title: title,
                icon: icon
            });

            marker.setMap(map);
        },
        updateMap: function(latitude, longitude) {
            marker.setMap(null);
            var newLatLng = new google.maps.LatLng(latitude,longitude);
            marker.position = newLatLng;
            marker.setMap(map);
            map.setCenter(newLatLng);
        }
    };
})();


做了上述這些改變以後,trackMap函數將變得非常有彈性了,不必依賴Google Maps API,相反可以任意替換其它的地圖提供商,那就是說可以按照程式的需求去適配任何地圖提供者。

何時依賴注入?

有點不太相關,其實依賴注入的概念常常和依賴倒置原則混在一起,為了澄清這個不同,我們有必要來解釋一下:

依賴注入是控制反轉的一個特殊形式,反轉的意思一個元件如何取得它的依賴。依賴注入的意思是:依賴提供給元件,而不是元件去獲取依賴,意思是建立一個依賴的實例,透過工廠去請求這個依賴,透過Service Locator或元件自身的初始化去請求這個依賴。依賴倒置原則和依賴注入都是關注依賴,而且都是用來反轉。不過,依賴倒置原則沒有關注元件如何獲取依賴,而是只關注高層模組如何從低層模組解耦出來。某種意義上說,依賴倒置原則是控制反轉的另一種形式,這裡反轉的是哪個模組定義介面(從低層定義,反轉到高層定義)。

總結

這是五大原則的最後一篇了,在這5篇文字裡我們看到了SOLID如何在JavaScript裡實現的,不同的原則在JavaScript里通過不同的角度來說明的。 (大叔註:其實大叔覺得雖然是有點不倫不類,但從另一個層面上說,大體的原則在各種語言上其實還是一樣的。)

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
es6数组怎么去掉重复并且重新排序es6数组怎么去掉重复并且重新排序May 05, 2022 pm 07:08 PM

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

JavaScript的Symbol类型、隐藏属性及全局注册表详解JavaScript的Symbol类型、隐藏属性及全局注册表详解Jun 02, 2022 am 11:50 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

原来利用纯CSS也能实现文字轮播与图片轮播!原来利用纯CSS也能实现文字轮播与图片轮播!Jun 10, 2022 pm 01:00 PM

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

JavaScript对象的构造函数和new操作符(实例详解)JavaScript对象的构造函数和new操作符(实例详解)May 10, 2022 pm 06:16 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

javascript怎么移除元素点击事件javascript怎么移除元素点击事件Apr 11, 2022 pm 04:51 PM

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

JavaScript面向对象详细解析之属性描述符JavaScript面向对象详细解析之属性描述符May 27, 2022 pm 05:29 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

foreach是es6里的吗foreach是es6里的吗May 05, 2022 pm 05:59 PM

foreach不是es6的方法。foreach是es3中一个遍历数组的方法,可以调用数组的每个元素,并将元素传给回调函数进行处理,语法“array.forEach(function(当前元素,索引,数组){...})”;该方法不处理空数组。

整理总结JavaScript常见的BOM操作整理总结JavaScript常见的BOM操作Jun 01, 2022 am 11:43 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),