JavaScript 設(shè)計(jì)模式(二):策略模式

策略模式

策略模式:定義一系列的算法,把它們一個(gè)個(gè)封裝起來(lái),并且使它們可以相互替換

生活小栗子:諸葛錦囊

諸葛給劉備的錦囊妙計(jì),遇到任何困難都有應(yīng)對(duì)計(jì)策。策略模式實(shí)現(xiàn)的也是類似的場(chǎng)景。

再來(lái)一栗:給喜歡的女生買冰淇淋,事先不了解其喜好,只能集齊各種味道,總會(huì)命中。就是比較 “費(fèi)錢”,這也是策略模式的缺點(diǎn),需事先考慮所有應(yīng)對(duì)場(chǎng)景。

模式特點(diǎn)

  1. 策略類:算法封裝成獨(dú)立的函數(shù)/對(duì)象
  2. 環(huán)境類:根據(jù)不同參數(shù)調(diào)用對(duì)應(yīng)的策略函數(shù)/對(duì)象執(zhí)行

模式實(shí)現(xiàn)

實(shí)現(xiàn)方式:一個(gè)基于策略模式的程序至少由兩部分組成,第一個(gè)部分是一組策略類 Strategies(可變),策略類封裝類具體的算法,并負(fù)責(zé)具體的計(jì)算過(guò)程。第二個(gè)部分是環(huán)境類 Context(不變), Context 接收客戶的請(qǐng)求,隨后把請(qǐng)求委托給某一個(gè)策略類。

假設(shè)我們一個(gè)開(kāi)發(fā)團(tuán)隊(duì),人員組成包括(開(kāi)發(fā)組長(zhǎng),后端,前端,測(cè)試)。開(kāi)發(fā)組長(zhǎng)領(lǐng)取開(kāi)發(fā)任務(wù)(不變),但具體的任務(wù)執(zhí)行人員可根據(jù)類型劃分(可變)。

比如開(kāi)發(fā)任務(wù)有以下幾項(xiàng):

  1. 優(yōu)化服務(wù)器緩存(后端任務(wù))
  2. 優(yōu)化首屏加載速度(前端任務(wù))
  3. 完成系統(tǒng)并發(fā)測(cè)試(測(cè)試任務(wù))

開(kāi)發(fā)組長(zhǎng)會(huì)根據(jù)任務(wù)類型,分發(fā)到對(duì)應(yīng)的開(kāi)發(fā)人員頭上,組長(zhǎng)不承擔(dān)具體開(kāi)發(fā)任務(wù)。所以每一個(gè)開(kāi)發(fā)人員就承擔(dān) Strategy 的作用(獨(dú)立的任務(wù)執(zhí)行),而組長(zhǎng)擁有并可支配所有開(kāi)發(fā)人員的資源,充當(dāng) Context 的角色。團(tuán)隊(duì)每一個(gè)開(kāi)發(fā)人員“組合”起來(lái)就是一個(gè) Strategies 類(執(zhí)行開(kāi)發(fā)任務(wù))。 這個(gè) Strategies 是可變的,如果說(shuō)后續(xù)開(kāi)發(fā)任務(wù)需要安卓的、IOS的支持,只要添加安卓、IOS開(kāi)發(fā)人員配置即可(可擴(kuò)展)。

// 策略類(開(kāi)發(fā)人員)
var Strategies = {
    "backend": function(task) {
        console.log('進(jìn)行后端任務(wù):', task);
    },
    "frontend": function(task) {
        console.log('進(jìn)行前端任務(wù):', task);
    },
    "testend": function(task) {
        console.log('進(jìn)行測(cè)試任務(wù):', task);
    }
};

//  環(huán)境類(開(kāi)發(fā)組長(zhǎng))
var Context = function(type, task) {
    typeof Strategies[type] === 'function' && Strategies[type](task);
}

Context('backend', '優(yōu)化服務(wù)器緩存');
Context('frontend', '優(yōu)化首頁(yè)加載速度');
Context('testend', '完成系統(tǒng)并發(fā)測(cè)試');

上述代碼帶來(lái)的好處:

  1. 算法獨(dú)立封裝,任務(wù)分發(fā);
    開(kāi)發(fā)組長(zhǎng)不承擔(dān)具體開(kāi)發(fā)任務(wù)(只做頂層設(shè)計(jì),不跟年輕人搶飯碗)
  2. 復(fù)用性更好,不局限于 Context 調(diào)用;
    開(kāi)發(fā)人員不愁下家(去哪寫代碼都是寫代碼)

策略模式的另一個(gè)好處就是,消除了大部分的 if...else / switch...case 條件分支語(yǔ)句,代碼閱讀性提高。

// 沒(méi)有使用策略模式的組長(zhǎng)...
var Context = function(type, task) {
    if (type === 'backend') {
        // 把后端給我叫來(lái)
    } else if (type === 'frontend') {
        // 把前端給我叫來(lái)
    } else if (type === 'testend') {
        // 把測(cè)試給我叫來(lái)
    }
}

JavaScript 中,函數(shù)作為“一等公民“,也稱“一等對(duì)象”。JavaScript 中 ”高階函數(shù)“ 應(yīng)用中,函數(shù)可被作為變量或參數(shù)進(jìn)行傳遞或調(diào)用。因此在 JavaScript 中,我們可將算法封裝成獨(dú)立的函數(shù),并將它作為參數(shù)傳遞給另一個(gè)函數(shù)調(diào)用。

// 封裝獨(dú)立的函數(shù)
var backend = function(task) {
    console.log('進(jìn)行后端任務(wù):', task);
};
var frontend = function(task) {
    console.log('進(jìn)行前端任務(wù):', task);
};
var testend = function(task) {
    console.log('進(jìn)行測(cè)試任務(wù):', task);
};

//  環(huán)境類(開(kāi)發(fā)組長(zhǎng))
var Context = function(func, task) {
    typeof func === 'function' && func(task);
}

Context(backend, '優(yōu)化服務(wù)器緩存');
Context(frontend, '優(yōu)化首頁(yè)加載速度');
Context(testend, '完成系統(tǒng)并發(fā)測(cè)試');

少了 Strategies 策略類的外層包裹,函數(shù)更加獨(dú)立,并不妨礙其調(diào)用。使用函數(shù)替代策略類方式,正是我們?nèi)粘i_(kāi)發(fā)中經(jīng)常用到的 “隱形” 策略模式。

適用場(chǎng)景

  1. 多重條件語(yǔ)句判斷,執(zhí)行對(duì)應(yīng)的算法場(chǎng)景
  2. 表單校驗(yàn)(validator)

優(yōu)缺點(diǎn)

  • 優(yōu)點(diǎn):
    1. 利用組合、委托、多態(tài)的技術(shù)和思想,避免多重條件選擇語(yǔ)句 if...else/switch...case;
    2. 復(fù)用性更高,算法函數(shù)可在系統(tǒng)其它地方使用;
    3. 支持設(shè)計(jì)模式 “開(kāi)發(fā)-封閉原則“ ,算法封裝在獨(dú)立的 Strategy 中,易于維護(hù)和擴(kuò)展;
    4. 策略模式使用 “組合和委托” 來(lái)讓 Context 擁有執(zhí)行算法的能力,一種替換對(duì)象繼承的可行方案
  • 缺點(diǎn):
    1. 增加了許多策略類或?qū)ο螅ㄩ_(kāi)發(fā)人員職能劃分明確,人員成本有所增加);
    2. 必須了解各個(gè) Strategy 的不同點(diǎn),違反 “最少知識(shí)原則”(組長(zhǎng)手底下有對(duì)應(yīng)的開(kāi)發(fā)人員,才不用自己那么苦逼)

參考文章

本文首發(fā)Github,期待Star!
https://github.com/ZengLingYong/blog

作者:以樂(lè)之名
本文原創(chuàng),有不當(dāng)?shù)牡胤綒g迎指出。轉(zhuǎn)載請(qǐng)指明出處。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • javascript設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐 設(shè)計(jì)模式 每個(gè)設(shè)計(jì)模式我們需要從三點(diǎn)問(wèn)題入手: 定義 作用 用法與實(shí)現(xiàn) 單...
    穿牛仔褲的蚊子閱讀 4,473評(píng)論 0 13
  • 在程序設(shè)計(jì)中,我們也常常遇到類似的情況,要實(shí)現(xiàn)某一個(gè)功能有多種方案可以選擇。比如一個(gè)壓縮文件的程序,既可以選擇zi...
    yufawu閱讀 438評(píng)論 0 3
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,639評(píng)論 1 32
  • 工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式。簡(jiǎn)單...
    舟漁行舟閱讀 8,118評(píng)論 2 17
  • 工廠模式 單體模式 模塊模式 代理模式 職責(zé)鏈模式 命令模式 模板方法模式 策略模式 發(fā)布-訂閱模式 中介者模式 ...
    HelloJames閱讀 1,076評(píng)論 0 6

友情鏈接更多精彩內(nèi)容