1. 程式人生 > >Javascript設計模式與開發實踐詳解(二:策略模式) http://www.jianshu.com/p/ef53781f6ef2

Javascript設計模式與開發實踐詳解(二:策略模式) http://www.jianshu.com/p/ef53781f6ef2

的人 思想 ram gis pan pro msg have 改變

上一章我們介紹了單例模式及JavaScript惰性單例模式應用
這一次我主要介紹策略模式
策略模式是定義一系列的算法,把它們一個個封裝起來,並且讓他們可以互相替換。
比方說在現實中很多時候也有很多途徑到達同一個目的地,比如我們去某個地方旅遊,可以選擇坐飛機,乘火車,騎自行車等方式。

使用策略模式計算獎金

很多公司的年終獎是根據員工的工資基數和年底績效來發放的。例如,績效為 S 的人年終獎有4倍工資,績效為 A 的人年終獎有3倍工資,績效為 B 的人年終獎有2倍工資。
現在我們來計算員工的年終獎。

  var performanceS = function  (salary) {
return salary * 4;
}
var performanceA = function  (salary) {
return salary * 3;
}
var performanceB = function  (salary) {
return salary * 2;
}
var calculateBonus = function  (performanceLevel,salary) {
if(performanceLevel === ‘S‘)
    return performanceS(salary)
if(performanceLevel === ‘A‘)
    return performanceA(salary)
if(performanceLevel === ‘B‘)
    return performanceB(salary)

}
calculateBonus(‘A‘,10000);  // 30000

值得一提的是以上代碼並不符合策略模式定義
策略模式是定義一系列的算法,把它們一個個封裝起來,並且讓他們可以互相替換。
這句話理解起來就是定義一系列的算法,把它們各自封裝成策略類,算法被封裝在策略類內部的方法裏。
因此我們必須做點改變

在JavaScript中,函數也是對象,所以我們可以直接將定義一個對象strategy用來存放策略類。
參見代碼:

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

以上基本符合了策略模式的定義及寫法。

更廣義的算法

用策略模式僅僅來封裝算法未免大材小用,在實際開發中,也可以用策略模式來封裝一些業務規則。
接下來我們用策略模式來完成表單驗證的例子。

表單驗證

校驗表單信息想必都是稀松平常的事情,假設我們正在編寫一個註冊的頁面,在點擊註冊按鈕之前,有如下幾條校驗邏輯。

1.用戶名不能為空
2.密碼長度不少於6位
3.手機號碼必須符合格式

假設我們現在沒有引入策略模式,那麽普通的寫法是這樣的:

<body>
 <form action=‘xxx‘ id=‘registerForm‘ method=‘post‘>
      please entry username : <input type=‘text‘ name=‘username‘ />
      please entry password : <input type=‘text‘ name=‘password‘ />
      please entry phoneNumber : <input type=‘text‘ name=‘phoneNumber‘ />
             <button>submit</button>
 </form>
 <script>
     var registerForm = document.getElementById(‘registerForm‘)
     registerForm.onsubmit = function  () {
         if(registerForm.username.value == ‘‘){
              alert(‘username cannot be none‘)
              return false;
         }
         if(registerForm.password.value.length < 6 ){
              alert(‘password length cannot less than 6‘)
              return false;
         }
         if(!/(^1[3][5][8][0-9]{9}$)/.test(registerForm.phoneNumber.value)){
             alert(‘phoneNumber format error‘)
             return false;
         }
     }
 </script>
</body>

可想而知這種面向過程的方法繁瑣且不復用缺乏彈性,總而言之,我們必須用策略模式重構之。

註意我們的核心思想就是要寫兩個類: 一個策略類 一個內容類

用策略模式重構表單校驗

第一步我們要把這些校驗邏輯封裝成策略對象,也就是策略類:

var strategies = {
 isNonEmpty: function  (value ,errorMsg) {
     if(value == ‘‘) return errorMsg
 },
 minLength: function  (value,length,errorMsg) {
     if(value.length < length) return errorMsg
 },
inMobile: function  (value,errorMsg) {
    if(!/(^1[3][5][8][0-9]{9}$)/.test(value)) return errorMsg 
}
};

ok ,現在我們開始寫內容類。Validator 類在這裏作為context ,負責接收用戶的請求,並委托給strategy對象。

var Validator = function  () {
this.cache = [];   // save the check format
}  
Validator.prototype.add = function  (dom,rule,errorMsg) {
var ary = rule.split(‘:‘)      // forExample : ‘minLength:10‘        
this.cache.push(function  () {
    var strategy = ary.shift() //  minLength
    ary.unshift(dom.value)     // forExample : registerForm.username
    ary.push(errorMsg);        //  ary= [registerForm.username,10]
     return strategies[strategy].apply(dom,ary)    //bring the dom & ary into strategies props.


});
};
Validator.prototype.start = function  () {
for (var i = 0; ValidatorFunc; ValidatorFunc = this.cache[i++]) {
     var msg = ValidatorFunc();
     if(msg) return msg;  // if have return value then the check is failed.
};
}

如果我們沒有寫如何用戶如何向Validator類發送請求,上面理解起來可能比較復雜。現在我們具體到表單看看。

var ValidatorFunc = function  () {
var validator = new Validator()
/***************add some format by the prototype     fun.*************************/
   validator.add(registerForm.username,‘isNonEmpty‘,‘username cannot be     none‘);
   validator.add(registerForm.password,‘minLength:6‘,‘password cannot be none‘);
   validator.add(registerForm.phoneNumber,‘isMoblie‘,‘phoneNumber cannot be none‘);


   var errorMsg = Validator.start() // get the check result 
   return errorMsg                  // return the result. if exsit ...
}

  var registerForm = document.getElementById(‘registerForm‘)
  registerForm.onsubmit = function  () {
  var errorMsg = validatorFunc()   // this is a instance!!!
  if(errorMsg) 
      alert(errorMsg)
  return false
}

這樣我們大致完成了一個表單的策略模式重構(如果你能馬上立刻看懂的話...)

值得一提的是我們現在可以非常輕松簡單的修改校驗規則,例如

validator.add(registerForm.username,‘minLength:10‘,‘username cannot less than 10‘)

小結

策略模式是一種常用且有效的設計模式,我們可以總結出策略模式的一些優點。

  1. 有效避免多重條件選擇語句
  2. 完美支持了開發--封閉原則
  3. 易於復用

Javascript設計模式與開發實踐詳解(二:策略模式) http://www.jianshu.com/p/ef53781f6ef2