日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
5分鐘即可掌握的前端高效利器:JavaScript策略模式

淺談 JavaScript 中策略模式的使用:

作為一家“創(chuàng)意+整合+營銷”的成都網(wǎng)站建設(shè)機(jī)構(gòu),我們在業(yè)內(nèi)良好的客戶口碑。創(chuàng)新互聯(lián)提供從前期的網(wǎng)站品牌分析策劃、網(wǎng)站設(shè)計、網(wǎng)站設(shè)計、網(wǎng)站建設(shè)、創(chuàng)意表現(xiàn)、網(wǎng)頁制作、系統(tǒng)開發(fā)以及后續(xù)網(wǎng)站營銷運(yùn)營等一系列服務(wù),幫助企業(yè)打造創(chuàng)新的互聯(lián)網(wǎng)品牌經(jīng)營模式與有效的網(wǎng)絡(luò)營銷方法,創(chuàng)造更大的價值。

  •  什么是設(shè)計模式
  •  什么是策略模式
  •  策略模式在 JavaScript 中的應(yīng)用(使用策略模式封裝百度AI識別調(diào)用)
  •  策略模式在 Vue 組件封裝中的應(yīng)用(使用策略模式封裝Select組件)

什么是設(shè)計模式

設(shè)想有一個電子愛好者,雖然他沒有經(jīng)過正規(guī)的培訓(xùn),但是卻日積月累地設(shè)計并制造出了許多有用的電子設(shè)備:業(yè)余無線電、蓋革計數(shù)器、報警器等。有一天這個愛好者決定重新回到學(xué)校去攻讀電子學(xué)學(xué)位,來讓自己的才能得到正式的認(rèn)可。隨著課程的展開,這個愛好者突然發(fā)現(xiàn)課程內(nèi)容都似曾相識。似曾相識的不是術(shù)語或表述的方式,而是背后的概念。這個愛好者不斷學(xué)到一些名稱和原理,雖然這些名稱和原理原來他并不知道,但事實上他多年以來一直都在使用。整個過程只不過是一個接一個的頓悟。

設(shè)計模式沉思錄 ,John Vlissides, 第一章 1.2節(jié)

我們在寫代碼的時候,一定也遇到過許多類似的場景。隨著經(jīng)驗的增加,我們對于這些常見場景的處理越來越得心應(yīng)手,甚至總結(jié)出了針對性的“套路”,下次遇到此類問題直接運(yùn)用“套路”解決,省心又省力。這些在軟件開發(fā)過程中逐漸積累下來的“套路”就是設(shè)計模式。

設(shè)計模式的目標(biāo)之一就是提高代碼的可復(fù)用性、可擴(kuò)展性和可維護(hù)性。正因如此,雖然有時候我們不知道某個設(shè)計模式,但是看了相關(guān)書籍或文章后會有一種“啊,原來這就是設(shè)計模式”的恍然大明白。

如果你看完這篇文章后也有此感覺,那么恭喜你,你已經(jīng)在高效程序員的道路上一路狂奔了。

什么是策略模式

策略模式是一種簡單卻常用的設(shè)計模式,它的應(yīng)用場景非常廣泛。我們先了解下策略模式的概念,再通過代碼示例來更清晰的認(rèn)識它。

策略模式由兩部分構(gòu)成:一部分是封裝不同策略的策略組,另一部分是 Context。通過組合和委托來讓 Context 擁有執(zhí)行策略的能力,從而實現(xiàn)可復(fù)用、可擴(kuò)展和可維護(hù),并且避免大量復(fù)制粘貼的工作。

策略模式的典型應(yīng)用場景是表單校驗中,對于校驗規(guī)則的封裝。接下來我們就通過一個簡單的例子具體了解一下:

粗糙的表單校驗

一個常見的登錄表單代碼如下: 

 
 
 
  1.   
  2.     手機(jī)號  
  3.       
  4.     密碼  
  5.       
  6.     登錄  
  7.   
  8.  

以上代碼,雖然功能沒問題,但是缺點也很明顯:

代碼里遍地都是 if 語句,并且它們?nèi)狈椥裕好啃略鲆环N、或者修改原有校驗規(guī)則,我們都必須去改loginForm.onsubmit內(nèi)部的代碼。另外邏輯的復(fù)用性也很差:如果有其它表單也是用同樣的規(guī)則,這段代碼并不能復(fù)用,只能復(fù)制。當(dāng)校驗規(guī)則發(fā)生變化時,比如上文的正則校驗并不能匹配虛擬運(yùn)營商14/17號段,我們就需要手動同步多處代碼變更(Ctrl+C/Ctrl+V)。

優(yōu)秀的表單驗證

接下來我們通過策略模式的思路改寫一下上段代碼,首先抽離并封裝校驗邏輯為策略組: 

 
 
 
  1. var strategies = {  
  2.     isNonEmpty: function (value, errorMsg) {  
  3.         if (value === '' || value === null) {  
  4.             return errorMsg;  
  5.         }  
  6.     },  
  7.     isMobile: function (value, errorMsg) { // 手機(jī)號碼格式  
  8.         if (!/(^1[3|4|5|7|8][0-9]{9}$)/.test(value)) {  
  9.             return errorMsg;  
  10.         }  
  11.     },  
  12.     minLength: function (value, length, errorMsg) {  
  13.         if (value.length < length) {  
  14.             return errorMsg;  
  15.         }  
  16.     }  
  17. }; 

接下來修改 Context: 

 
 
 
  1. var loginForm = document.getElementById('login-form');  
  2. loginForm.onsubmit = function (e) {  
  3.     e.preventDefault();   
  4.     var accountIsMobile = strategies.isMobile(account,'手機(jī)號格式錯誤');  
  5.     var pwdMinLength = strategies.minLength(pwd,8,'密碼不能小于8位');  
  6.     var errorMsg = accountIsMobile||pwdMinLength;   
  7.     if(errorMsg){  
  8.         alert(errorMsg); 
  9.          return false;  
  10.     } 

對比兩種實現(xiàn),我們可以看到:分離了校驗邏輯的代碼如果需要擴(kuò)展校驗類型,在策略組中新增定義即可使用;如果需要修改某個校驗的實現(xiàn),直接修改相應(yīng)策略即可全局生效。對于開發(fā)和維護(hù)都有明顯的效率提升。

擴(kuò)展:史詩的表單校驗

有興趣的朋友可以了解下 async-validator ,element-ui 和 antd 的表單校驗都是基于 async-validator 封裝的,可以說是史詩級別的表單校驗了

通過表單校驗的對比,相信大家都對策略模式有所了解,那么接下來通過兩個例子具體了解下 JavaScript 中策略模式的應(yīng)用:

使用策略模式調(diào)用百度AI圖像識別

因為百度AI圖像識別的接口類型不同,所需的參數(shù)格式也不盡相同。然而圖像的壓縮及上傳、錯誤處理等部分是公用的。所以可以采用策略模式封裝:

定義策略組

通過定義策略組來封裝不同的接口及其參數(shù):比如身份證識別接口的side字段,自定義識別的templateSign字段,以及行駛證識別的接收參數(shù)為poparamstData。 

 
 
 
  1. /**  
  2.  * 策略組  
  3.  * IDCARD:身份證識別  
  4.  * CUSTOMIZED:自定義識別  
  5.  * VL:行駛證識別  
  6.  */  
  7. var strategies = {  
  8.     IDCARD: function (base64) {  
  9.         return {  
  10.             path: 'idcard',  
  11.             param: {  
  12.                 'side': 'front',  
  13.                 'base64': base64  
  14.             }  
  15.         };  
  16.     },  
  17.     CUSTOMIZED: function (base64) {  
  18.         return {  
  19.             path: 'customized',  
  20.             param: {  
  21.                 'templateSign': '52cc2d402155xxxx',  
  22.                 'base64': base64  
  23.             }  
  24.         };  
  25.     },  
  26.     VL: function (base64) {  
  27.         return {  
  28.             path: 'vehicled',  
  29.             poparamstData: {  
  30.                 'base64': base64  
  31.             }  
  32.         };  
  33.     },  
  34. }; 

定義 Context 

 
 
 
  1. var ImageReader = function () { };  
  2. /**  
  3.  * 讀取圖像,調(diào)用接口,獲取識別結(jié)果  
  4.  *   
  5.  * @param {*} type 待識別文件類型  
  6.  * @param {*} base64 待識別文件 BASE64碼  
  7.  * @param {*} callBack 識別結(jié)果回調(diào)  
  8.  */  
  9. ImageReader.prototype.getOcrResult = function (type, base64, callBack) {  
  10.     let fileSize = (base64.length / (1024 * 1024)).toFixed(2);  
  11.     let compressedBase64 = '';  
  12.     let image = new Image();  
  13.     image.src = base64;  
  14.     image.onload = function () {  
  15.         /**  
  16.          * 圖片壓縮處理及異常處理,代碼略  
  17.          */     
  18.         let postData = strategies[type](compressedBase64); 
  19.         ajax( 
  20.             host + postData.path, {  
  21.                 data: postData.param,  
  22.                 type: 'POST',  
  23.                 headers: {  
  24.                     'Content-Type': 'application/x-www-form-urlencoded'  
  25.                 },  
  26.                 success: function (res) {  
  27.                     var data = JSON.parse(res);  
  28.                     // 暴露給 UI 層的統(tǒng)一的錯誤碼  
  29.                     if (data.error_code !== undefined && data.error_code !== 0) {  
  30.                         var errorData = {  
  31.                             error: 1,  
  32.                             title: '錯誤 ' + data.error_code,  
  33.                             content: 'error message'  
  34.                         };  
  35.                         callBack(errorData);  
  36.                     } else {  
  37.                         callBack(data);  
  38.                     }  
  39.                 }  
  40.             });  
  41.     };  
  42. }; 

調(diào)用方式 

 
 
 
  1. var imageReader = new ImageReader();  
  2. imageReader.getOcrResult('IDCARD', this.result.toString(), callback); 

使用策略模式封裝 Vue Select 組件

某項目中多處用到了 element-ui 的 select 組件,其內(nèi)在邏輯類似,都是初始化時獲取下拉列表的數(shù)據(jù)源,然后在選中某一項時 dispatch 不同的 action。遂考慮使用策略模式封裝。

Context

在本例中,組件向外部暴露一個 prop,調(diào)用方指定該 prop 從而加載不同的策略。那么定義 Context 如下: 

 
 
 
  1.   
 
 
 
  1. data() {  
  2.     return {  
  3.       selectedValue: undefined,  
  4.       options: [],  
  5.       action: "",  
  6.     };  
  7.   },  
  8.   props: {  
  9.     // 暴露給外部的 select-type  
  10.     selectType: {  
  11.       type: String  
  12.     },  
  13.   },  
  14.   created() {  
  15.    // 獲取 options  
  16.    this.valuation();  
  17.   },  
  18.     methods: {  
  19.     optionChanged() {  
  20.       this.$emit(this.action, this.selectedValue);  
  21.     },  
  22.     setOptions(option) {  
  23.       this.$store.dispatch(this.action, option);  
  24.     },  
  25.     valuation() {  
  26.       // 獲取 options 數(shù)據(jù)  
  27.     }  
  28.   }, 

外部通過如下方式調(diào)用組件:

 
 
 
  1.  

strategies

然后定義策略組: 

 
 
 
  1. let strategies = {  
  2.     source: {  
  3.         action: "sourceOption",  
  4.         getOptions:  function() {  
  5.             // 拉取 options  
  6.         }  
  7.     },  
  8.     product: {  
  9.         action: "productOption",  
  10.         getOptions:  function() {  
  11.             // 拉取 options  
  12.         }  
  13.     },  
  14.     ...  

異步

至此該組件的基本結(jié)構(gòu)已經(jīng)清晰,但還存在一個問題:組件加載時是異步拉取的 options, 而頁面初始化的時候很可能 options 還沒有返回,導(dǎo)致 select 的 options 仍為空。所以此處應(yīng)該修改代碼,同步獲取 options: 

 
 
 
  1. // 策略組修改  
  2. source: {  
  3.     action: "sourceOption",  
  4.     getOptions: async function() {  
  5.         // await 拉取 options  
  6.     }  
  7.   },  
  8. // 組件修改  
  9. methods: {  
  10.     ...  
  11.     async valuation() {  
  12.         ...  
  13.     }  

繼續(xù)優(yōu)化

但我們不是每次加載組件都需要拉取 options,如果這些 options 在其他組件或者頁面也被使用到,那么可以考慮將其存入 vuex 中。

最開始的思路是高階組件,即定義一個包裝后的select模板,通過高階組件的方式擴(kuò)展其數(shù)據(jù)源與action(變化的部分)然而這個思路不是那么的vue(主要是slots不太好處理) 于是考慮策略模式改寫該組件

總結(jié)

通過以上兩個例子,我們可以看到:

  •  策略模式符合開放-封閉原則
  •  如果代碼里需要寫大量的if-else語句,那么考慮使用策略模式
  •  如果多個組件(類)之間的區(qū)別僅在于它們的行為,考慮采用策略模式 

網(wǎng)站題目:5分鐘即可掌握的前端高效利器:JavaScript策略模式
URL地址:http://m.5511xx.com/article/dppihdj.html