深入理解JavaScript系列(22):S.O.L.I.D五大原則之依賴倒置原則DIP詳解
來(lái)源:易賢網(wǎng) 閱讀:782 次 日期:2015-03-09 17:23:47
溫馨提示:易賢網(wǎng)小編為您整理了“深入理解JavaScript系列(22):S.O.L.I.D五大原則之依賴倒置原則DIP詳解”,方便廣大網(wǎng)友查閱!

這篇文章主要介紹了深入理解JavaScript系列(22):S.O.L.I.D五大原則之依賴倒置原則DIP詳解,本文講解了DIP and JavaScript、何時(shí)依賴注入等內(nèi)容,需要的朋友可以參考下

前言

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

英文原文:

依賴倒置原則

依賴倒置原則的描述是:

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.

高層模塊不應(yīng)該依賴于低層模塊,二者都應(yīng)該依賴于抽象

B. Abstractions should not depend upon details. Details should depend upon abstractions.

抽象不應(yīng)該依賴于細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴于抽象

依賴倒置原則的最重要問(wèn)題就是確保應(yīng)用程序或框架的主要組件從非重要的底層組件實(shí)現(xiàn)細(xì)節(jié)解耦出來(lái),這將確保程序的最重要的部分不會(huì)因?yàn)榈蛯哟谓M件的變化修改而受影響。

該原則的第一部分是關(guān)于高層模塊和低層模塊之間的耦合方式,在傳統(tǒng)的分成架構(gòu)中,高層模塊(封裝了程序的核心業(yè)務(wù)邏輯)總依賴于低層的一些模塊(一些基礎(chǔ)點(diǎn))。當(dāng)應(yīng)用依賴倒置原則的時(shí)候,關(guān)系就反過(guò)來(lái)了。和高層模塊依賴于低層模塊不同,依賴倒置是讓低層模塊依賴于高層模塊里定義的接口。舉例來(lái)說(shuō),如果要給程序進(jìn)行數(shù)據(jù)持久化,傳統(tǒng)的設(shè)計(jì)是核心模塊依賴于一個(gè)持久化模塊的API,而根據(jù)依賴倒置原則重構(gòu)以后,則是核心模塊需要定義持久化的API接口,然后持久化的實(shí)現(xiàn)實(shí)例需要實(shí)現(xiàn)核心模塊定義的這個(gè)API接口。

該原則的第二部分描述的是抽象和細(xì)節(jié)之間的正確關(guān)系。理解這一部分,通過(guò)了解C++語(yǔ)言比較有幫助,因?yàn)樗倪m用性比較明顯。

不像一些靜態(tài)類型的語(yǔ)言,C++沒(méi)有提供一個(gè)語(yǔ)言級(jí)別的概念來(lái)定義接口,那類定義和類實(shí)現(xiàn)之間到底是怎么樣的呢,在C++里,類通過(guò)頭文件的形式來(lái)定義,其中定義了源文件需要實(shí)現(xiàn)的類成員方法和變量。因?yàn)樗械淖兞亢退接蟹椒ǘ级x在頭文件里,所以可以用來(lái)抽象以便和實(shí)現(xiàn)細(xì)節(jié)之前解耦出來(lái)。通過(guò)定只定義抽象方法來(lái)實(shí)現(xiàn)(C++里是抽象基類)接口這個(gè)概念用于實(shí)現(xiàn)類來(lái)實(shí)現(xiàn)。

DIP and JavaScript

因?yàn)镴avaScript是動(dòng)態(tài)語(yǔ)言,所以不需要去為了解耦而抽象。所以抽象不應(yīng)依賴于細(xì)節(jié)這個(gè)改變?cè)贘avaScript里沒(méi)有太大的影響,但高層模塊不應(yīng)依賴于低層模塊卻有很大的影響。

在當(dāng)靜態(tài)類型語(yǔ)言的上下文里討論依賴倒置原則的時(shí)候,耦合的概念包括語(yǔ)義(semantic)和物理(physical)兩種。這就是說(shuō),如果一個(gè)高層模塊依賴于一個(gè)低層模塊,也就是不僅耦合了語(yǔ)義接口,也耦合了在底層模塊里定義的物理接口。也就是說(shuō)高層模塊不僅要從第三方類庫(kù)解耦出來(lái),也需要從原生的低層模塊里解耦出來(lái)。

為了解釋這一點(diǎn),想象一個(gè).NET程序可能包含一個(gè)非常有用的高層模塊,而該模塊依賴于一個(gè)低層的持久化模塊。當(dāng)作者需要在持久化API里增加一個(gè)類似的接口的時(shí)候,不管依賴倒置原則有沒(méi)有使用,高層模塊在不重新實(shí)現(xiàn)這個(gè)低層模塊的新接口之前是沒(méi)有辦法在其它的程序里得到重用的。

在JavaScript里,依賴倒置原則的適用性僅僅限于高層模塊和低層模塊之間的語(yǔ)義耦合,比如,DIP可以根據(jù)需要去增加接口而不是耦合低層模塊定義的隱式接口。

為了來(lái)理解這個(gè),我們看一下如下例子:

代碼如下:

$.fn.trackMap = function(options) {

var defaults = {

/* defaults */

};

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

var mapOptions = {

center: 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,

title: options.title,

icon: options.icon

});

marker.setMap(map);

options.feed.update(function(latitude, longitude) {

marker.setMap(null);

var newLatLng = new google.maps.LatLng(latitude, longitude);

marker.position = newLatLng;

marker.setMap(map);

map.setCenter(newLatLng);

});

return this;

};

var updater = (function() {

// private properties

return {

update: function(callback) {

updateMap = callback;

}

};

})();

$("#map_canvas").trackMap({

latitude: 35.044640193770725,

longitude: -89.98193264007568,

icon: 'http://bit.ly/zjnGDe',

title: 'Tracking Number: 12345',

feed: updater

});

在上述代碼里,有個(gè)小型的JS類庫(kù)將一個(gè)DIV轉(zhuǎn)化成Map以便顯示當(dāng)前跟蹤的位置信息。trackMap函數(shù)有2個(gè)依賴:第三方的Google Maps API和Location feed。該feed對(duì)象的職責(zé)是當(dāng)icon位置更新的時(shí)候調(diào)用一個(gè)callback回調(diào)(在初始化的時(shí)候提供的)并且傳入緯度latitude和精度longitude。Google Maps API是用來(lái)渲染界面的。

feed對(duì)象的接口可能按照裝,也可能沒(méi)有照裝trackMap函數(shù)的要求去設(shè)計(jì),事實(shí)上,他的角色很簡(jiǎn)單,著重在簡(jiǎn)單的不同實(shí)現(xiàn),不需要和Google Maps這么依賴。介于trackMap語(yǔ)義上耦合了Google Maps API,如果需要切換不同的地圖提供商的話那就不得不對(duì)trackMap函數(shù)進(jìn)行重寫(xiě)以便可以適配不同的provider。

為了將于Google maps類庫(kù)的語(yǔ)義耦合翻轉(zhuǎn)過(guò)來(lái),我們需要重寫(xiě)設(shè)計(jì)trackMap函數(shù),以便對(duì)一個(gè)隱式接口(抽象出地圖提供商provider的接口)進(jìn)行語(yǔ)義耦合,我們還需要一個(gè)適配Google Maps API的一個(gè)實(shí)現(xiàn)對(duì)象,如下是重構(gòu)后的trackMap函數(shù):

復(fù)制代碼 代碼如下:

$.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

});

在該版本里,我們重新設(shè)計(jì)了trackMap函數(shù)以及需要的一個(gè)地圖提供商接口,然后將實(shí)現(xiàn)的細(xì)節(jié)挪到了一個(gè)單獨(dú)的googleMapsProvider組件,該組件可能獨(dú)立封裝成一個(gè)單獨(dú)的JavaScript模塊。如下是我的googleMapsProvider實(shí)現(xiàn):

代碼如下:

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函數(shù)將變得非常有彈性了,不必依賴于Google Maps API,相反可以任意替換其它的地圖提供商,那就是說(shuō)可以按照程序的需求去適配任何地圖提供商。

何時(shí)依賴注入?

有點(diǎn)不太相關(guān),其實(shí)依賴注入的概念經(jīng)常和依賴倒置原則混在一起,為了澄清這個(gè)不同,我們有必要來(lái)解釋一下:

依賴注入是控制反轉(zhuǎn)的一個(gè)特殊形式,反轉(zhuǎn)的意思一個(gè)組件如何獲取它的依賴。依賴注入的意思就是:依賴提供給組件,而不是組件去獲取依賴,意思是創(chuàng)建一個(gè)依賴的實(shí)例,通過(guò)工廠去請(qǐng)求這個(gè)依賴,通過(guò)Service Locator或組件自身的初始化去請(qǐng)求這個(gè)依賴。依賴倒置原則和依賴注入都是關(guān)注依賴,并且都是用于反轉(zhuǎn)。不過(guò),依賴倒置原則沒(méi)有關(guān)注組件如何獲取依賴,而是只關(guān)注高層模塊如何從低層模塊里解耦出來(lái)。某種意義上說(shuō),依賴倒置原則是控制反轉(zhuǎn)的另外一種形式,這里反轉(zhuǎn)的是哪個(gè)模塊定義接口(從低層里定義,反轉(zhuǎn)到高層里定義)。

總結(jié)

這是五大原則的最后一篇了,在這5篇文字里我們看到了SOLID如何在JavaScript里實(shí)現(xiàn)的,不同的原則在JavaScript里通過(guò)不同的角度來(lái)說(shuō)明的。

更多信息請(qǐng)查看IT技術(shù)專欄

更多信息請(qǐng)查看腳本欄目
由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢回復(fù)僅供參考,敬請(qǐng)考生以權(quán)威部門公布的正式信息和咨詢?yōu)闇?zhǔn)!

2025國(guó)考·省考課程試聽(tīng)報(bào)名

  • 報(bào)班類型
  • 姓名
  • 手機(jī)號(hào)
  • 驗(yàn)證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡(jiǎn)要咨詢 | 簡(jiǎn)要咨詢須知 | 加入群交流 | 手機(jī)站點(diǎn) | 投訴建議
工業(yè)和信息化部備案號(hào):滇ICP備2023014141號(hào)-1 云南省教育廳備案號(hào):云教ICP備0901021 滇公網(wǎng)安備53010202001879號(hào) 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號(hào)
云南網(wǎng)警備案專用圖標(biāo)
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號(hào):hfpxwx
咨詢QQ:526150442(9:00—18:00)版權(quán)所有:易賢網(wǎng)
云南網(wǎng)警報(bào)警專用圖標(biāo)