策略模式
定義:定義一系列的算法罐寨,把他們一個個封裝起來,并且使他們可以相互替換
看一個例子(取自 js 設計模式與開發(fā)實踐)
例如序矩,績效為 S 的人年終獎是 4 倍工資鸯绿,績效為 A 的人年終獎是 3 倍工資,績效為 B 的人年終獎是 2 倍工資
看一段代碼
var bonus = function (level, salary) {
if (level === "S") {
return salary * 4;
}
if (level === "A") {
return salary * 3;
}
if (level === "B") {
return salary * 2;
}
};
bonus("S", 1000);
這段代碼的問題在哪里簸淀,有很多的 if,函數(shù)缺乏彈性楞慈,如果再添加一種績效,則需要深入函數(shù)內(nèi)部啃擦,修改函數(shù)囊蓝,所以我們看看使用策略模式后代碼
var strategies = {
S: function (salary) {
return salary * 4;
},
A: function (salary) {
return salary * 3;
},
B: function (salary) {
return salary * 2;
},
};
var calculateBonus = function (level, salary) {
return strategies[level](salary);
};
console.log(calculateBonus("S", 20000)); // 輸出:80000
console.log(calculateBonus("A", 10000)); // 輸出:30000
這樣算法的使用和算法的實現(xiàn)就分離開了,相互不再影響
代碼看著很簡單令蛉,能否想到用策略模式來優(yōu)化代碼聚霜,以及實現(xiàn),我想這需要一定的積累才能達到珠叔。
再看一個例子加強一下(取自 js 設計模式與開發(fā)實踐)
表單校驗
<html>
<body>
<form action="http:// xxx.com/register" id="registerForm" method="post">
請輸入用戶名:<input type="text" name="userName" /> 請輸入密碼:<input
type="text"
name="password"
/>
請輸入手機號碼:<input type="text" name="phoneNumber" />
<button>提交</button>
</form>
<script>
var registerForm = document.getElementById("registerForm");
registerForm.onsubmit = function () {
if (registerForm.userName.value === "") {
alert("用戶名不能為空");
return false;
}
if (registerForm.password.value.length < 6) {
alert("密碼長度不能少于6 位");
return false;
}
if (!/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value)) {
alert("手機號碼格式不正確");
return false;
}
};
</script>
</body>
</html>
沒有使用策略設計模式蝎宇,代碼中依然存在很多的 if (這給我們一個提示,如果我們寫的代碼含有大量的 if else 那么我們是不是可以用策略模式來優(yōu)化我們的代碼呢祷安?姥芥,也許以后我們遇到的時候可以停下來思考一下是否可以優(yōu)化)
使用策略模式后的代碼
<html>
<body>
<form action="http:// xxx.com/register" id="registerForm" method="post">
請輸入用戶名:<input type="text" name="userName" /> 請輸入密碼:<input
type="text"
name="password"
/>
請輸入手機號碼:<input type="text" name="phoneNumber" />
<button>提交</button>
</form>
<script>
/***********************策略對象**************************/
var strategies = {
isNonEmpty: function (value, errorMsg) {
if (value === "") {
return errorMsg;
}
},
minLength: function (value, length, errorMsg) {
if (value.length < length) {
return errorMsg;
}
},
isMobile: function (value, errorMsg) {
if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
return errorMsg;
}
},
};
/***********************Validator 類**************************/
var Validator = function () {
this.cache = [];
};
Validator.prototype.add = function (dom, rules) {
var self = this;
for (var i = 0, rule; (rule = rules[i++]); ) {
(function (rule) {
var strategyAry = rule.strategy.split(":");
var errorMsg = rule.errorMsg;
self.cache.push(function () {
var strategy = strategyAry.shift();
strategyAry.unshift(dom.value);
strategyAry.push(errorMsg);
return strategies[strategy].apply(dom, strategyAry);
});
})(rule);
}
};
Validator.prototype.start = function () {
for (var i = 0, validatorFunc; (validatorFunc = this.cache[i++]); ) {
var errorMsg = validatorFunc();
if (errorMsg) {
return errorMsg;
}
}
};
/***********************客戶調(diào)用代碼**************************/
var registerForm = document.getElementById("registerForm");
var validataFunc = function () {
var validator = new Validator();
validator.add(registerForm.userName, [
{
strategy: "isNonEmpty",
errorMsg: "用戶名不能為空",
},
{
strategy: "minLength:6",
errorMsg: "用戶名長度不能小于10 位",
},
]);
validator.add(registerForm.password, [
{
strategy: "minLength:6",
errorMsg: "密碼長度不能小于6 位",
},
]);
var errorMsg = validator.start();
return errorMsg;
};
registerForm.onsubmit = function () {
var errorMsg = validataFunc();
if (errorMsg) {
alert(errorMsg);
return false;
}
};
</script>
</body>
</html>
這段代碼,建議多閱讀幾遍汇鞭,體會一下策略模式