策略模式:定義一系列的算法,把它們一個個封裝起來,並且使它們可以相互替換
生活小栗子:諸葛錦囊
諸葛給劉備的錦囊妙計,遇到任何困難都有應對計策。策略模式實現的也是類似的場景。
再來一慄:給喜歡的女生買冰淇淋,事先不瞭解其喜好,只能集齊各種味道,總會命種。就是比較 “費錢”,這也是策略模式的缺點,需事先考慮所有應對場景。
模式特點
- 策略類:算法封裝成獨立的函數/對象
- 環境類:根據不同參數調用對應的策略函數/對象執行
模式實現
實現方式:一個基於策略模式的程序至少由兩部分組成,第一個部分是一組策略類 Strategies(可變),策略類封裝類具體的算法,並負責具體的計算過程。第二個部分是環境類 Context(不變), Context 接收客戶的請求,隨後把請求委託給某一個策略類。
假設我們一個開發團隊,人員組成包括(開發組長,後端,前端,測試)。開發組長領取開發任務(不變),但具體的任務執行人員可根據類型劃分(可變)。
比如開發任務有以下幾項:
- 優化服務器緩存(後端任務)
- 優化首屏加載速度(前端任務)
- 完成系統併發測試(測試任務)
開發組長會根據任務類型,分發到對應的開發人員頭上,組長不承擔具體開發任務。所以每一個開發人員就承擔 Strategy 的作用(獨立的任務執行),而組長擁有並可支配所有開發人員的資源,充當 Context 的角色。團隊每一個開發人員“組合”起來就是一個 Strategies 類(執行開發任務)。 這個 Strategies 是可變的,如果說後續開發任務需要安卓的、IOS的支持,只要添加安卓、IOS開發人員配置即可(可擴展)。
// 策略類(開發人員)
var Strategies = {
"backend": function(task) {
console.log('進行後端任務:', task);
},
"frontend": function(task) {
console.log('進行前端任務:', task);
},
"testend": function(task) {
console.log('進行測試任務:', task);
}
};
// 環境類(開發組長)
var Context = function(type, task) {
typeof Strategies[type] === 'function' && Strategies[type](task);
}
Context('backend', '優化服務器緩存');
Context('frontend', '優化首頁加載速度');
Context('testend', '完成系統併發測試');
上述代碼帶來的好處:
- 算法獨立封裝,任務分發;
開發組長不承擔具體開發任務(只做頂層設計,不跟年輕人搶飯碗) - 複用性更好,不侷限於 Context 調用;
開發人員不愁下家(去哪寫代碼都是寫代碼)
策略模式的另一個好處就是,消除了大部分的 if...else
/ switch...case
條件分支語句,代碼閱讀性提高。
// 沒有使用策略模式的組長...
var Context = function(type, task) {
if (type === 'backend') {
// 把後端給我叫來
} else if (type === 'frontend') {
// 把前端給我叫來
} else if (type === 'testend') {
// 把測試給我叫來
}
}
JavaScript 中,函數作爲“一等公民“,也稱“一等對象”。JavaScript 中 ”高階函數“ 應用中,函數可被作爲變量或參數進行傳遞或調用。因此在 JavaScript 中,我們可將算法封裝成獨立的函數,並將它作爲參數傳遞給另一個函數調用。
// 封裝獨立的函數
var backend = function(task) {
console.log('進行後端任務:', task);
};
var frontend = function(task) {
console.log('進行前端任務:', task);
};
var testend = function(task) {
console.log('進行測試任務:', task);
};
// 環境類(開發組長)
var Context = function(func, task) {
typeof func === 'function' && func(task);
}
Context(backend, '優化服務器緩存');
Context(frontend, '優化首頁加載速度');
Context(testend, '完成系統併發測試');
少了 Strategies 策略類的外層包裹,函數更加獨立,並不妨礙其調用。使用函數替代策略類方式,正是我們日常開發中經常用到的 “隱形” 策略模式。
適用場景
- 多重條件語句判斷,執行對應的算法場景
- 表單校驗(validator)
優缺點
-
優點:
- 利用組合、委託、多態的技術和思想,避免多重條件選擇語句
if...else/switch...case
; - 複用性更高,算法函數可在系統其它地方使用;
- 支持設計模式 “開發-封閉原則“ ,算法封裝在獨立的 Strategy 中,易於維護和擴展;
- 策略模式使用 “組合和委託” 來讓 Context 擁有執行算法的能力,一種替換對象繼承的可行方案
- 利用組合、委託、多態的技術和思想,避免多重條件選擇語句
-
缺點:
- 增加了許多策略類或對象(開發人員職能劃分明確,人員成本有所增加);
- 必須瞭解各個 Strategy 的不同點,違反 “最少知識原則”(組長手底下有對應的開發人員,纔不用自己那麼苦逼)
JavaScript設計模式整理系列正在更新中,敬請關注專欄 "前端進擊的巨人",獲取實時更新。
參考文章
本文首發Github,期待Star!
https://github.com/ZengLingYong/blog
作者:以樂之名
本文原創,有不當的地方歡迎指出。轉載請指明出處。