前言:要提升代碼水平,就繞不開設計模式。之前也有過一些瞭解,但並沒有深入學習。最近準備系統的學習一下設計模式,提高設計,解耦的能力,發現了一本好書《JavaScript設計模式與開發實踐》,所以邊讀邊寫,把常用的設計模式學習並記錄在這裏。
定義與介紹
單例模式的定義:定義一系列算法,把它們一個個封裝起來,並且使它們可以互相替換。
策略模式是最親民的設計模式了,即使之前沒學過,在很多代碼中我們都會不知不覺的使用簡單的策略模式,但本篇簡述的完整策略模式更加的面向對象。
JavaScript中的策略模式
在JavaScript
中,函數也是對象,最直接的做法就是把策略直接定義爲函數:
// 根據績效和工資計算年終獎的例子:
// 根據績效不同,有不同的算法,把這些算法封裝成不同的策略
const strategies = {
S: function(salary) {
return salary * 4;
},
A: function(salary) {
return salary * 3;
},
B: function(salary) {
return salary * 2;
}
}
const calculateBouns = function(level, salary) {
return strategies[level](salary);
}
calculateBouns(S, 10000);
可以看到,上邊的做法其實不需要學習,我們在日常編碼中就很可能會自發的這樣使用,僅僅針對這個例子而言,甚至可以更加簡潔。當然這樣做有好有壞,可以根據實際情況決定,如下:
const strategies = {
S: 4,
A: 3,
B: 2,
}
const calculateBouns = function(level, salary) {
return strategies[level] * salary;
}
calculateBouns(A, 20000);
策略模式的例子
我們有個很常見的表單校驗需求,希望這些校驗規則能夠方便的替換和組合使用,來預防後期的需求變更。
// 表單結構
<html>
<body>
<form action='xxx' id='registerForm' method="POST">
請輸入用戶名:<input type='text' name='userName' />
請輸入密碼:<input type='text' name='password' />
請輸入手機號:<input type='text' name='mobile' />
</form>
</body>
<html>
// js
/******* 策略對象 ********/
const strategies = {
isNotEmpty: function(val, errMsg) {
if(val === '') {
return errMsg
}
},
minLength: function(val, minLen, errMsg) {
if(val.length < minLen) {
return errMsg
}
},
isMobile: function(val, errMsg) {
if(!/(^1[3|5|8][0-9]{9}$)/.test(val)) {
return errMsg
}
}
}
/******* Validator 類 ********/
class Validator {
constructor() {
this.cache = [];
}
add(dom, rules) {
rules.forEach(rule => {
const strategyArr = rule.strategy.aplit(':');
const errMsg = rule.errMsg;
// catch中保存的是校驗方法
this.catch.push(function() {
// 取出冒號左邊的策略名稱
// 如 minLen: 6,爲最小長度爲6位
const strategy = strategyArr.shift();
// 把實際的輸入值從左側插入參數數組
strategyArr.unshift(dom.value);
// 把錯誤提示從右側插入參數數組
strategyArr.push(errMsg);
// 取得對應的策略,使用apply在dom下執行,傳入參數數組strategyArr
return strategies[strategy].apply(dom, strategyArr);
})
})
}
start() {
this.cacht.forEach(validatorFunc => {
const errMsg = validatorFunc();
if (errMsg) {
return errMsg;
}
})
}
}
/******* 調用代碼 ********/
const registerForm = document.getElementById('registerForm');
const validataFunc = function() {
const validator = new Validator();
// 校驗對象增加校驗規則
validator.add(registerForm.userName, [{
strategy: 'isNotEmpty',
errMsg: '用戶名不能爲空',
}, {
strategy: 'minLen: 10',
errMsg: '用戶名長度不能小於10位',
}]);
validator.add(registerForm.password, [{
strategy: 'minLen: 6',
errMsg: '用戶名長度不能小於6位',
}]);
validator.add(registerForm.mobile, [{
strategy: 'isMobile',
errMsg: '手機號碼格式不正確',
}]);
// 校驗對象開始校驗
const errMsg = validator.start();
return errMsg;
}
registerForm.onsubmit = function() {
const errMsg = validataFunc();
if(errMsg) {
alert(errMsg);
return
}
// do submit
}