在軟體工程中,設計模式(design pattern)是對軟體設計中廣泛存在(反覆出現)的各類問題,所提出的解決方案。javascript
設計模式並不直接用來完成程式碼的編寫,而是描述在各類不一樣狀況下,要怎麼解決問題的一種方案。java
設計模式能使不穩定轉爲相對穩定、具體轉爲相對抽象,避免會引發麻煩的緊耦合,以加強軟體設計面對並適應變化的能力git
——維基百科github
設計模式是一種軟件開發的思想,有益於下降代碼的耦合性,加強代碼的健壯性。每每在大型項目中用的比較多。算法
今天就來介紹一種能夠替代選擇運算的設計模式——策略模式。設計模式
策略模式做爲一種軟件設計模式,指對象有某個行爲,可是在不一樣的場景中,該行爲有不一樣的實現算法。好比每一個人都要「交我的所得稅」,可是「在美國交我的所得稅」和「在中國交我的所得稅」就有不一樣的算稅方法。單元測試
策略模式:學習
- 定義了一族算法(業務規則);
- 封裝了每一個算法;
- 這族的算法可互換代替(interchangeable)。
——維基百科測試
能夠看出,爲應對不一樣場景所致使算法不一樣,基於工廠模式將各個算法進行封裝成類,再進行使用,這就是策略模式。ui
咱們來一個例子,通常狀況下,若是咱們要作數據合法性驗證,不少時候都是按照 swith 語句來判斷(也能夠是 if,elseif,else 的結構),可是這就帶來幾個問題:
代碼以下:
validator = {
validate: function(value, type) {
switch (type) {
case "isNonEmpty ": {
return true;
}
case "isNumber ": {
return true;
break;
}
case "isAlphaNum ": {
return true;
}
default: {
return true;
}
}
}
};
// 測試
alert(validator.validate("123", "isNonEmpty"));
複製代碼
那如何來避免上述代碼中的問題呢,根據策略模式,咱們能夠將相同的工做代碼單獨封裝成不一樣的類,而後經過統一的策略處理類來處理,OK,咱們先來定義策略處理類,代碼以下:
var validator = {
// 全部能夠的驗證規則處理類存放的地方,後面會單獨定義
types: {},
// 驗證類型所對應的錯誤消息
messages: [],
// 固然須要使用的驗證類型
config: {},
// 暴露的公開驗證方法
// 傳入的參數是 key => value對
validate: function(data) {
var i, msg, type, checker, result_ok;
// 清空全部的錯誤信息
this.messages = [];
for (i in data) {
if (data.hasOwnProperty(i)) {
type = this.config[i]; // 根據key查詢是否有存在的驗證規則
checker = this.types[type]; // 獲取驗證規則的驗證類
if (!type) {
continue; // 若是驗證規則不存在,則不處理
}
if (!checker) {
// 若是驗證規則類不存在,拋出異常
throw {
name: "ValidationError",
message: "No handler to validate type " + type
};
}
result_ok = checker.validate(data[i]); // 使用查到到的單個驗證類進行驗證
if (!result_ok) {
msg = "Invalid value for *" + i + "*, " + checker.instructions;
this.messages.push(msg);
}
}
}
return this.hasErrors();
},
// helper
hasErrors: function() {
return this.messages.length !== 0;
}
};
複製代碼
而後剩下的工做,就是定義 types 裏存放的各類驗證類了,咱們這裏只舉幾個例子:
// 驗證給定的值是否不爲空
validator.types.isNonEmpty = {
validate: function(value) {
return value !== "";
},
instructions: "傳入的值不能爲空"
};
// 驗證給定的值是不是數字
validator.types.isNumber = {
validate: function(value) {
return !isNaN(value);
},
instructions: "傳入的值只能是合法的數字,例如:1, 3.14 or 2010"
};
// 驗證給定的值是否只是字母或數字
validator.types.isAlphaNum = {
validate: function(value) {
return !/[^a-z0-9]/i.test(value);
},
instructions: "傳入的值只能保護字母和數字,不能包含特殊字符"
};
複製代碼
使用的時候,咱們首先要定義須要驗證的數據集合,而後還須要定義每種數據須要驗證的規則類型,代碼以下:
var data = {
first_name: "Tom",
last_name: "Xu",
age: "unknown",
username: "TomXu"
};
validator.config = {
first_name: "isNonEmpty",
age: "isNumber",
username: "isAlphaNum"
};
複製代碼
最後,獲取驗證結果的代碼就簡單了:
validator.validate(data);
if (validator.hasErrors()) {
console.log(validator.messages.join("\n"));
}
複製代碼
策略模式定義了一系列算法,從概念上來講,全部的這些算法都是作相同的事情,只是實現不一樣,他能夠以相同的方式調用全部的方法,減小了各類算法類與使用算法類之間的耦合。
從另一個層面上來講,單獨定義算法類,也方便了單元測試,由於能夠經過本身的算法進行單獨測試。
實踐中,不只能夠封裝算法,也能夠用來封裝幾乎任何類型的規則,是要在分析過程當中須要在不一樣時間應用不一樣的業務規則,就能夠考慮是要策略模式來處理各類變化。
-EFO-
筆者專門在 github 上建立了一個倉庫,用於記錄平時學習全棧開發中的技巧、難點、易錯點,歡迎你們點擊下方連接瀏覽。若是以爲還不錯,就請給個小星星吧!👍
2019/04/24