成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

5分鐘即可掌握的前端高效利器:JavaScript 策略模式

BlackFlagBin / 1045人閱讀

摘要:策略模式由兩部分構(gòu)成一部分是封裝不同策略的策略組,另一部分是。策略模式的典型應(yīng)用場景是表單校驗中,對于校驗規(guī)則的封裝。然而圖像的壓縮及上傳錯誤處理等部分是公用的。遂考慮使用策略模式封裝。

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

什么是設(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é)位,來讓自己的才能得到正式的認可。隨著課程的展開,這個愛好者突然發(fā)現(xiàn)課程內(nèi)容都似曾相識。似曾相識的不是術(shù)語或表述的方式,而是背后的概念。這個愛好者不斷學(xué)到一些名稱和原理,雖然這些名稱和原理原來他并不知道,但事實上他多年以來一直都在使用。整個過程只不過是一個接一個的頓悟。

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

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

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

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

什么是策略模式

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

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

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

粗糙的表單校驗

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

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

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

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

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

var strategies = {
    isNonEmpty: function (value, errorMsg) {
        if (value === "" || value === null) {
            return errorMsg;
        }
    },
    isMobile: function (value, errorMsg) { // 手機號碼格式
        if (!/(^1[3|4|5|7|8][0-9]{9}$)/.test(value)) {
            return errorMsg;
        }
    },
    minLength: function (value, length, errorMsg) {
        if (value.length < length) {
            return errorMsg;
        }
    }
};

接下來修改 Context:

var loginForm = document.getElementById("login-form");

loginForm.onsubmit = function (e) {
    e.preventDefault(); 
    var accountIsMobile = strategies.isMobile(account,"手機號格式錯誤");
    var pwdMinLength = strategies.minLength(pwd,8,"密碼不能小于8位");
    var errorMsg = accountIsMobile||pwdMinLength; 
    if(errorMsg){
        alert(errorMsg);
        return false;
    }
}

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

擴展:史詩的表單校驗

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

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

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

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

定義策略組

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

/**
 * 策略組
 * IDCARD:身份證識別
 * CUSTOMIZED:自定義識別
 * VL:行駛證識別
 */
var strategies = {
    IDCARD: function (base64) {
        return {
            path: "idcard",
            param: {
                "side": "front",
                "base64": base64
            }
        };
    },

    CUSTOMIZED: function (base64) {
        return {
            path: "customized",
            param: {
                "templateSign": "52cc2d402155xxxx",
                "base64": base64
            }
        };
    },
    VL: function (base64) {
        return {
            path: "vehicled",
            poparamstData: {
                "base64": base64
            }
        };
    },
};
定義 Context
var ImageReader = function () { };

/**
 * 讀取圖像,調(diào)用接口,獲取識別結(jié)果
 * 
 * @param {*} type 待識別文件類型
 * @param {*} base64 待識別文件 BASE64碼
 * @param {*} callBack 識別結(jié)果回調(diào)
 */
ImageReader.prototype.getOcrResult = function (type, base64, callBack) {
    let fileSize = (base64.length / (1024 * 1024)).toFixed(2);
    let compressedBase64 = "";
    let image = new Image();
    image.src = base64;
    image.onload = function () {
        /**
         * 圖片壓縮處理及異常處理,代碼略
         */
         

        let postData = strategies[type](compressedBase64);

        ajax(
            host + postData.path, {
                data: postData.param,
                type: "POST",
                headers: {
                    "Content-Type": "application/x-www-form-urlencoded"
                },
                success: function (res) {
                    var data = JSON.parse(res);
                    // 暴露給 UI 層的統(tǒng)一的錯誤碼
                    if (data.error_code !== undefined && data.error_code !== 0) {
                        var errorData = {
                            error: 1,
                            title: "錯誤 " + data.error_code,
                            content: "error message"
                        };
                        callBack(errorData);
                    } else {
                        callBack(data);
                    }
                }
            });
    };
};

調(diào)用方式
var imageReader = new ImageReader();
imageReader.getOcrResult("IDCARD", this.result.toString(), callback);
使用策略模式封裝 Vue Select 組件

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

Context

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

data() {
    return {
      selectedValue: undefined,
      options: [],
      action: "",
    };
  },
  props: {
    // 暴露給外部的 select-type
    selectType: {
      type: String
    },
  },
  created() {
   // 獲取 options
   this.valuation();
  },
    methods: {
    optionChanged() {
      this.$emit(this.action, this.selectedValue);
    },
    setOptions(option) {
      this.$store.dispatch(this.action, option);
    },
    valuation() {
      // 獲取 options 數(shù)據(jù)
    }
  },

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

strategies

然后定義策略組:

let strategies = {
    source: {
        action: "sourceOption",
        getOptions:  function() {
            // 拉取 options
        }
    },
    product: {
        action: "productOption",
        getOptions:  function() {
            // 拉取 options
        }
    },
    ...
}
異步

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

// 策略組修改
source: {
    action: "sourceOption",
    getOptions: async function() {
        // await 拉取 options
    }
  },
// 組件修改
methods: {
    ...
    async valuation() {
        ...
    }
}
繼續(xù)優(yōu)化

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

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

總結(jié)

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

策略模式符合開放-封閉原則

如果代碼里需要寫大量的if-else語句,那么考慮使用策略模式

如果多個組件(類)之間的區(qū)別僅在于它們的行為,考慮采用策略模式

參考
JavaScript設(shè)計模式與開發(fā)實踐(曾探) 第五章 策略模式

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/97495.html

相關(guān)文章

  • 前端資源收集整理

    摘要:工作原因,最近一年斷斷續(xù)續(xù)寫了一點前端代碼,收集整理了一些資料,和大家共享。 工作原因,最近一年斷斷續(xù)續(xù)寫了一點前端代碼,收集整理了一些資料,和大家共享。 Github版本:Front-End Resource Collection 前端相關(guān)資源匯總 學(xué)習(xí)指導(dǎo) 精華文章 Web前端的路該怎么走?:文章超長,但是干貨超級多,值得反復(fù)精讀! 聽說2017你想寫前端?:適合于已經(jīng)度過了小白階...

    awesome23 評論0 收藏0
  • 前端資源收集整理

    摘要:工作原因,最近一年斷斷續(xù)續(xù)寫了一點前端代碼,收集整理了一些資料,和大家共享。 工作原因,最近一年斷斷續(xù)續(xù)寫了一點前端代碼,收集整理了一些資料,和大家共享。 Github版本:Front-End Resource Collection 前端相關(guān)資源匯總 學(xué)習(xí)指導(dǎo) 精華文章 Web前端的路該怎么走?:文章超長,但是干貨超級多,值得反復(fù)精讀! 聽說2017你想寫前端?:適合于已經(jīng)度過了小白階...

    antyiwei 評論0 收藏0
  • 前端資源收集整理

    摘要:工作原因,最近一年斷斷續(xù)續(xù)寫了一點前端代碼,收集整理了一些資料,和大家共享。 工作原因,最近一年斷斷續(xù)續(xù)寫了一點前端代碼,收集整理了一些資料,和大家共享。 Github版本:Front-End Resource Collection 前端相關(guān)資源匯總 學(xué)習(xí)指導(dǎo) 精華文章 Web前端的路該怎么走?:文章超長,但是干貨超級多,值得反復(fù)精讀! 聽說2017你想寫前端?:適合于已經(jīng)度過了小白階...

    KavenFan 評論0 收藏0
  • 前端 - 收藏集 - 掘金

    摘要:是目前唯一一個支持同步調(diào)用的跨平臺年度上最多的個項目前端掘金年接近尾聲,在最近的幾篇文章中,會整理總結(jié)一些年度開源項目。 JS 全棧教程 - 前端 - 掘金本課程是基于阮一峰的 js 全棧教程的視頻版本,免費供大家觀看... 2016 年 10 個最佳的 CodePen 作品 - 前端 - 掘金說到 CodePen,前端開發(fā)者們肯定不會陌生。如果說 Dribbble 是設(shè)計師們聚集的圣...

    honhon 評論0 收藏0
  • 前端相關(guān)匯總

    摘要:簡介前端發(fā)展迅速,開發(fā)者富有的創(chuàng)造力不斷的給前端生態(tài)注入新生命,各種庫框架工程化構(gòu)建工具層出不窮,眼花繚亂,不盲目追求前沿技術(shù),學(xué)習(xí)框架和庫在滿足自己開發(fā)需求的基礎(chǔ)上,然后最好可以對源碼進行調(diào)研,了解和深入實現(xiàn)原理,從中可以獲得更多的收獲隨 showImg(https://segmentfault.com/img/remote/1460000016784101?w=936&h=397)...

    BenCHou 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<