適配器的別名是包裝器(wrapper
),這是一個相對簡單的模式。在程序開發中有許多這樣的場景:當我們試圖調用模塊或者對象的某個接口時,卻發現這個接口的格式并不符合目前的需求。這時候有兩種解決辦法,第一種是修改原來的接口實現,但如果原來的模塊很復雜,或者我們拿到的模塊是一段別人編寫的經過壓縮的代碼,修改原接口就顯得不太現實了。第二種辦法是創建一個適配器,將原接口轉換為客戶希望的另一個接口,客戶只需要和適配器打交道。
現實中也有很多適配器的例子:電源插座,usb適配器等等;例如iPhone7以后的耳機接口從3.5mm圓孔接口更改成為了蘋果專屬的 lightning接口。許多人以前的圓孔耳機就需要下面的一個適配器,才能夠在自個兒新買的iPhone上面聽歌。
當我們向googleMap 和
baiduMap都發出“顯示”請求時,
googleMap和
baiduMap` 分別以各自的方式在頁面中展現了地圖
const googleMap = { show: function () { console.log('開始渲染谷歌地圖'); } };const baiduMap = { show: function () { console.log('開始渲染百度地圖'); } };const renderMap = function (map) { if (map.show instanceof Function) { map.show(); } }; renderMap(googleMap); //
這段程序得以順利運行的關鍵是googleMap
和baiduMap
提供了一致的show
方法,但第三方的接口方法并不在我們自己的控制范圍之內,假如baiduMap
提供的顯示地圖的方法不叫show
而叫display
呢?
baiduMap
這個對象來源于第三方,正常情況下我們都不應該去改動它,而且有時候我們也改不了它。此時我們可以通過增加baiduMapAdapter
來解決問題:
const googleMap = { show: function () { console.log('開始渲染谷歌地圖'); } };const baiduMap = { display: function () { console.log('開始渲染百度地圖'); } };const baiduMapAdapter = { show: function(){ return baiduMap.display(); } }; renderMap(googleMap); //
有的情況下一個方法可能需要傳入多個參數,例如在做一些監控上報的SDK時,可能采集的數據比較多,這個類中有一個systemInfo
,需要傳入五個參數用于接收手機的相關信息:
class SDK { systemInf(brand, os, carrier, language, network) { //dosomething..... } }
通常在傳入的參數大于3的時候,我們就可以考慮將參數合并為一個對象的形式,就像我們$.ajax
的做法一樣。下面我們可以將systemInfo
的參數接口定義如下(String代表參數類型,?:
代表可選項)
{ brand: String os: String carrier:? String language:? String network:? String}
可以看出,carrier、language,network這三個屬性不是必須傳入的,它們在方法內部可能被設置一些默認值。所以這個時候我們就可以在方法內部采用適配器來適配這個參數對象。這種方式在我們的插件或者npm包中是常見的;
class SDK { systemInf(config) { let defaultConfig = { brand: null, //手機品牌 os: null, //系統類型: Andoird或 iOS carrier: 'china-mobile', //運營商,默認中國移動 language: 'zh', //語言類型,默認中文 network: 'wifi', //網絡類型,默認wifi } //參數適配 for( let i in config) { defaultConfig[i] = config[i] || defaultConfig[i]; } //dosomething..... } }
數據的適配在前端中是最為常見的場景,這時適配器在解決前后端的數據依賴上有著重要的意義。通常服務器端傳遞的數據和我們前端需要使用的數據格式是不一致的,特別是在在使用一些UI框架時,框架所規定的數據有著固定的格式。所以,這個時候我們就需要對后端的數據格式進行適配。
例如網頁中有一個使用Echarts折線圖對網站每周的uv,通常后端返回的數據格式如下所示:
[ { "day": "周一", "uv": 6300 }, { "day": "周二", "uv": 7100 }, { "day": "周三", "uv": 4300 }, { "day": "周四", "uv": 3300 }, { "day": "周五", "uv": 8300 }, { "day": "周六", "uv": 9300 }, { "day": "周日", "uv": 11300 } ]
但是Echarts需要的x軸的數據格式和坐標點的數據是長下面這樣的:
["周二", "周二", "周三", "周四", "周五", "周六", "周日"] //x軸的數據[6300. 7100, 4300, 3300, 8300, 9300, 11300] //坐標點的數據
所以這是我們就可以使用一個適配器,將后端的返回數據做適配:
//x軸適配器function echartXAxisAdapter(res) { return res.map(item => item.day); }//坐標點適配器function echartDataAdapter(res) { return res.map(item => item.uv); }
適配器模式是一對相對簡單的模式。但適配器模式在JS中的使用場景很多,在參數的適配上,有許多庫和框架都使用適配器模式;數據的適配在解決前后端數據依賴上十分重要。我們要認識到的是適配器模式本質上是一個”亡羊補牢”的模式,它解決的是現存的兩個接口之間不兼容的問題,你不應該在軟件的初期開發階段就使用該模式;如果在設計之初我們就能夠統籌的規劃好接口的一致性,那么適配器就應該盡量減少使用。
在JavaScript中的適配器更多應用于在對象之間,為了使對象可用,我們通常會將對象拆分并重新組裝,這樣就必須了解適配對象的內部結構,這也是和外觀模式的區別所在,當然是配資模式同樣解決了對象之間的耦合度,包裝的適配代碼增加了一些資源消耗,但這是微乎其微的。
相關文章:
設計模式(適配器)
JavaScript設計模式系列五:適配器模式
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com