自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

適配器在JavaScript中的體現(xiàn)

開發(fā) 前端
適配器設(shè)計(jì)模式在JavaScript中非常有用,在處理跨瀏覽器兼容問題、整合多個第三方SDK的調(diào)用,都可以看到它的身影。

適配器設(shè)計(jì)模式在JavaScript中非常有用,在處理跨瀏覽器兼容問題、整合多個第三方SDK的調(diào)用,都可以看到它的身影。

其實(shí)在日常開發(fā)中,很多時候會不經(jīng)意間寫出符合某種設(shè)計(jì)模式的代碼,畢竟設(shè)計(jì)模式就是老前輩們總結(jié)提煉出來的一些能夠幫助提升開發(fā)效率的一些模版,源于日常的開發(fā)中。

而適配器其實(shí)在JavaScript中應(yīng)該是比較常見的一種了。

在維基百科中,關(guān)于適配器模式的定義為:

在軟件工程中,適配器模式是一種軟件設(shè)計(jì)模式,允許從另一個接口使用現(xiàn)有類的接口。它通常用于使現(xiàn)有的類與其他類一起工作,而無需修改其源代碼。

生活中的例子

在生活中最常見的就是電源插頭的適配器了,世界各國的插座標(biāo)準(zhǔn)各不相同,如果需要根據(jù)各國的標(biāo)準(zhǔn)購買對應(yīng)的電源插頭那未免太過于浪費(fèi)錢財,如果說自己帶著插座,把人家墻敲碎,重新接線,也肯定是不現(xiàn)實(shí)的。

所以就會有插頭的適配器,用來將某種插頭轉(zhuǎn)換成另一種插頭,在插座和你的電源之間做中轉(zhuǎn)的這個東西,就是適配器。

[[245771]]

在代碼中的體現(xiàn)

而轉(zhuǎn)向到編程中,我個人是這樣理解的:

將那些你不愿意看見的臟代碼藏起來,你就可以說這是一個適配器

接入多個第三方SDK

舉個日常開發(fā)中的例子,我們在做一個微信公眾號開發(fā),里邊用到了微信的支付模塊,經(jīng)過長時間的聯(lián)調(diào),終于跑通了整個流程,正當(dāng)你準(zhǔn)備開心的打包上線代碼的時候,得到了一個新需求:

我們需要接入支付寶公眾號的SDK,也要有支付的流程

為了復(fù)用代碼,我們可能會在腳本中寫下這樣的邏輯: 

  1. if (platform === 'wechat') {  
  2.   wx.pay(config)  
  3. } else if (platform === 'alipay') {  
  4.   alipay.pay(config)  
  5.  
  6. // 做一些后續(xù)的邏輯處理 

但是一般來說,各廠的SDK所提供的接口調(diào)用方式都會多多少少有些區(qū)別,雖說有些時候文檔可能用的是同一份,致敬友商。

所以針對上述的代碼可能是這樣的: 

  1. // 并不是真實(shí)的參數(shù)配置,僅僅舉例使用  
  2. const config = {  
  3.   price: 10,  
  4.   goodsId: 1  
  5.  
  6. // 還有可能返回值的處理方式也不相同  
  7. if (platform === 'wechat') {  
  8.   config.appId = 'XXX'  
  9.   config.secretKey = 'XXX'  
  10.   wx.pay(config).then((err, data) => {  
  11.     if (err) // error  
  12.     // success  
  13.   })  
  14. } else if (platform === 'alipay') {  
  15.   config.token = 'XXX'  
  16.   alipay.pay(config, data => {  
  17.     // success  
  18.   }, err => {  
  19.     // error  
  20.   })  

就目前來說,代碼接口還算是清晰,只要我們寫好注釋,這也不是一個太糟糕的代碼。

但是生活總是充滿了意外,我們又接到了需求需要添加QQ的SDK、美團(tuán)的SDK、小米的SDK,或者某些銀行的SDK。

此時你的代碼可能是這樣的: 

  1. switch (platform) {  
  2.   case 'wechat':  
  3.     // 微信的處理邏輯  
  4.   break  
  5.   case 'QQ':  
  6.     // QQ的處理邏輯  
  7.   break  
  8.   case 'alipay':  
  9.     // 支付寶的處理邏輯  
  10.   break  
  11.   case 'meituan':  
  12.     // 美團(tuán)的處理邏輯  
  13.   break  
  14.   case 'xiaomi':  
  15.     // 小米的處理邏輯  
  16.   break  

這已經(jīng)不是一些注釋能夠彌補(bǔ)的問題了,這樣的代碼會變得越來越難維護(hù),各種SDK千奇百怪的調(diào)用方式,如果其他人也要做類似的需求,還需要重新寫一遍這樣的代碼,那肯定是很浪費(fèi)資源的一件事兒。

所以為了保證我們業(yè)務(wù)邏輯的清晰,同時也為了避免后人重復(fù)的踩這個坑,我們會將它進(jìn)行拆分出來作為一個公共的函數(shù)來存在:

找到其中某一個SDK的調(diào)用方式或者一個我們約定好的規(guī)則作為基準(zhǔn)。

我們來告訴調(diào)用方,你要怎么怎么做,你能怎樣獲取返回數(shù)據(jù),然后我們在函數(shù)內(nèi)部進(jìn)行這些各種骯臟的判斷: 

  1. function pay ({  
  2.   price,  
  3.   goodsId  
  4. }) {  
  5.   return new Promise((resolve, reject) => {  
  6.     const config = {}  
  7.     switch (platform) {  
  8.       case 'wechat':  
  9.         // 微信的處理邏輯  
  10.         config.price = price  
  11.         config.goodsId = goodsId  
  12.         config.appId = 'XXX'  
  13.         config.secretKey = 'XXX'  
  14.         wx.pay(config).then((err, data) => {  
  15.           if (err) return reject(err)  
  16.           resolve(data)  
  17.         })  
  18.       break  
  19.       case 'QQ':  
  20.         // QQ的處理邏輯  
  21.         config.price = price * 100  
  22.         config.gid = goodsId  
  23.         config.appId = 'XXX'  
  24.         config.secretKey = 'XXX'  
  25.         config.success = resolve  
  26.         config.error = reject  
  27.         qq.pay(config)  
  28.       break  
  29.       case 'alipay':  
  30.         // 支付寶的處理邏輯  
  31.         config.payment = price  
  32.         config.id = goodsId  
  33.         config.token = 'XXX'  
  34.         alipay.pay(config, resolve, reject)  
  35.       break  
  36.     }  
  37.   })  

這樣無論我們在什么環(huán)境下,只要我們的適配器支持,就可以按照我們約定好的通用規(guī)則進(jìn)行調(diào)用,而具體執(zhí)行的是什么SDK,則是適配器需要關(guān)心的事情: 

  1. // run anywhere  
  2. await pay({  
  3.   price: 10,  
  4.   goodsId: 1  
  5. }) 

對于SDK提供方,僅僅需要知道自己所需要的一些參數(shù),然后按照自己的方式進(jìn)行數(shù)據(jù)返回。

對于SDK調(diào)用房,僅僅需要我們約定好的通用的參數(shù),以及按照約定的方式進(jìn)行監(jiān)聽回調(diào)處理。

整合多個第三方SDK的任務(wù)就交由適配器來做,然后我們將適配器的代碼壓縮,混淆,放在一個看不見的角落里去,這樣的代碼邏輯就會變得很清晰了 :)。

適配器大致就是這樣的作用,有一點(diǎn)一定要明確,適配器不是銀彈,__那些繁瑣的代碼始終是存在的,只不過你在寫業(yè)務(wù)的時候看不到它罷了__,眼不見心不煩。

一些其他的例子

個人覺得,jQuery中就有很多適配器的例子,包括最基礎(chǔ)的$('selector').on,這個不就是一個很明顯的適配器模式么?

一步步的進(jìn)行降級,并且抹平了一些瀏覽器之間的差異,讓我們可以通過簡單的on來進(jìn)行在主流瀏覽器中進(jìn)行事件監(jiān)聽: 

  1. // 一個簡單的偽代碼示例  
  2. function on (target, event, callback) {  
  3.   if (target.addEventListener) {  
  4.     // 標(biāo)準(zhǔn)的監(jiān)聽事件方式  
  5.     target.addEventListener(event, callback)  
  6.   } else if (target.attachEvent) {  
  7.     // IE低版本的監(jiān)聽方式  
  8.     target.attachEvent(event, callback)  
  9.   } else {  
  10.     // 一些低版本的瀏覽器監(jiān)聽事件方式  
  11.     target[`on${event}`] = callback  
  12.   }  

或者在Node中的這樣的例子更是常見,因?yàn)樵缒晔菦]有Promise的,所以大多數(shù)的異步由callback來完成,且有一個約定好的規(guī)則,Error-first callback: 

  1. const fs = require('fs')  
  2. fs.readFile('test.txt', (err, data) => {  
  3.   if (err) // 處理異常  
  4.   // 處理正確結(jié)果  
  5. }) 

而我們的新功能都采用了async/await的方式來進(jìn)行,當(dāng)我們需要復(fù)用一些老項(xiàng)目中的功能時,直接去修改老項(xiàng)目的代碼肯定是不可行的。

這樣的兼容處理需要調(diào)用方來做,所以為了讓邏輯代碼看起來不是太混亂,我們可能會將這樣的回調(diào)轉(zhuǎn)換為Promise的版本方便我們進(jìn)行調(diào)用: 

  1. const fs = require('fs')  
  2. function readFile (fileName) {  
  3.   return new Promise((resolve, reject) => {  
  4.     fs.readFile(fileName, (err, data) => {  
  5.       if (err) reject(err)  
  6.       resolve(data)  
  7.     })  
  8.   })  
  9.  
  10. await readFile('test.txt') 

因?yàn)榍斑呉蔡岬搅耍@種Error-first callback是一個約定好的形式,所以我們可以很輕松的實(shí)現(xiàn)一個通用的適配器: 

  1. function promisify(func) {  
  2.   return (...args) => new Promise((resolve, reject) => {  
  3.     func(...args, (err, data) => {  
  4.       if (err) reject(err)  
  5.       resolve(data)  
  6.     })  
  7.   })  

然后在使用前進(jìn)行對應(yīng)的轉(zhuǎn)換就可以用我們預(yù)期的方式來執(zhí)行代碼: 

  1. const fs = require('fs')  
  2. const readFile = promisify(fs.readFile)  
  3. await readFile('test.txt') 

在Node8中,官方已經(jīng)實(shí)現(xiàn)了類似這樣的工具函數(shù):util.promisify 

小結(jié)

個人觀點(diǎn):所有的設(shè)計(jì)模式都不是憑空想象出來的,肯定是在開發(fā)的過程中,總結(jié)提煉出的一些高效的方法,這也就意味著,可能你并不需要在剛開始的時候就去生啃這些各種命名高大上的設(shè)計(jì)模式。

因?yàn)闀兴f的場景可能并不全面,也可能針對某些語言,會存在更好的解決辦法,所以生搬硬套可能并不會寫出有靈魂的代碼 :)

紙上得來終覺淺,絕知此事要躬行。 ———— 《冬夜讀書示子聿》,陸游 

責(zé)任編輯:龐桂玉 來源: 前端大全
相關(guān)推薦

2021-02-16 08:16:09

適配器模式MybatisJava

2012-09-19 15:29:26

Worklight適配器

2012-12-10 10:53:04

IBMdW

2015-08-07 10:05:37

recyclervie超省寫法

2012-04-12 09:33:02

JavaScript

2022-02-18 17:21:29

適配器模式客戶端

2020-10-25 08:56:21

適配器模式

2022-02-13 23:33:24

設(shè)計(jì)模式Java

2021-08-06 06:51:16

適配器配置Spring

2011-04-28 09:54:50

jQuery

2013-11-26 16:39:21

Android設(shè)計(jì)模式

2021-02-18 08:39:28

設(shè)計(jì)模式場景

2012-05-16 17:22:11

Java設(shè)計(jì)模式

2009-11-18 18:08:20

PHP適配器模式

2009-12-21 10:26:09

Oracle適配器

2012-08-02 10:46:34

JavaAdapter模式

2010-07-09 12:53:30

HART協(xié)議

2014-12-17 09:57:01

AndroidAdapteViewHolder

2013-02-26 10:55:47

C#適配器設(shè)計(jì)模式

2010-12-23 13:56:34

網(wǎng)絡(luò)適配器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號