讀書筆記之策略模式

最近在看《javascript設計模式與開發(fā)實踐》。

var calc = function(level,salary){
         if(level === "A"){
            return 3*salary
         }
         if(level === "B"){
            return 2*salary
         }
         if(level === "C"){
            return 1*salary
         }
}

這段代碼看起來十分簡單,但是隨著后期的拓展,要添加更多的if語句,calc函數(shù)會變得更加龐大,不易于維護。
如果我要修改原有的計算分之,可能每次都要修改calc這個方法。實際上,這個calc這個方法的設計初衷只是為了返回 績效工資。
在整個代碼的其它部分,可能還需要這個計算方法,難道還要copy一份過去么,那么同樣的修改要修改兩塊代碼。

用策略模式來重構(gòu)代碼

  • 策略模式指的是定義一系列的算法,把他們一個個都封裝起來。將不變的部分和變化的部分分割開始每個設計模式的主題,策略模式的目的就是將算法的使用與算法的實現(xiàn)分離開來。

  • 再說上邊的需求,我們簡單思考下,其實變化的部分就是員工的等級和工資,而我們的目的就是返回績效工資這部分是不變的

//  根據(jù)員工的level和salary 金額的計算
var straigies = {
    “A”: function(salary){
        return fn*3
    },
    “B”: function(salary){
        return fn*2
    },
    “C”: function(salary){
        return fn*1
    }
}
//不變的部分
var calc = function(level,salary){
     return straigies[level](salary)
}
// 執(zhí)行
calc("A",5000)    // => 15000

比較下兩段代碼,不見了不友好的 if判斷,算法(策略)都放在了straigies 中,后續(xù)需求 只需要維護straigies對象即可。

  • 用策略模式來重構(gòu)表單驗證

很多需要提交表單的業(yè)務場景,都需要如下結(jié)構(gòu)的代碼

$('submitBtn').on('click',functioin(){
    if($name.value().length < 6){
         console.log("用戶名長度不能少于6")
    }
   if($phone.value() != ''){
        console.log("電話號碼不能為空")
 }
  ajaxFn()
})

隨著 判斷條件的增加,函數(shù)的結(jié)構(gòu)會越來越臃腫龐大,而需要修改判斷的條件,就又要深入指定的if判斷去篩選,單純的新增規(guī)則在這個函數(shù)里,復用性太差。結(jié)合策略模式,可以把if判斷這一部分 函數(shù)里提取出來重新封裝,提高代碼的復用性和可讀性。

對代碼結(jié)構(gòu)的期望

$('submitBtn').on('click',functioin(){
  var form = document.querySelector('.form');
  var validator = new validator ();
  validator.addrules(form.username,"isNonEmpty","不能為空")
  validator.addrules(form.phone,"minLength:6","最少為6位")
  var erroMsg = validator.start();
  if(erroMsg){
     alert(validator);
     return false
  }
  ajaxFn()
})

我們先封裝策略類

var stratigies = {
    isNonEmpty: function(value,erromsg){
          if(value == ""){
          return erromsg
        }
    },
  minlength: function(value,length,erromsg){
       if(value.length < length){
          return erromsg
      }
 }
}

封裝 驗證(validator類)

var Validator = function(){
  this.cache = [] //用來緩存
}
Validator.prototype.add = function(item,rule,erroMsg){
  var arg = rule.split(":") // rule= >  "isEmpty" => ["isEmpty"] ||  "minLength:5"=> ["minlength", “5”];
  this.cache.push(function(){
      var strategy = arg.shift();  // =>"isEmpty" || minLength
      arg.unshift(item.value);  //[value] || [value,5]
      arg.push(errMsg)// [value,errMsg] || [value,5,errMsg]
      return  stratigies[strategy].apply(item,arg)
  })
}
//start方法就是遍歷這個Validator里緩存的方法并執(zhí)行
Validator.prototype.start = function(){
  for(var i=0;i<this.cache.length;i++){
      var fn = this.cache[i];
      var msg = fn()    // =>開始校驗,
      if(msg){
         return msg   // 如果msg有值 就說明驗證不通過,跳出循環(huán)
      }
  }
}

此時,如果需要添加規(guī)則 或是修改驗證規(guī)則,就很簡單了
我們可以在stratigies里添加策略,也可以在 提交表單的函數(shù)里,新增或者修改規(guī)則

validator.addrules(form.phone,"minLength:6") =》 validator.addrules(form.phone,"minLength:10")

很蛋疼的是,對用戶名判斷只能一次輸入一種規(guī)則,如果需要加一種判斷規(guī)則,我就要在add一次strategy,
書中提供了進一步的拓展。

//預期
  validator.addrules(form.username,[
   {
      "erroMsg": "不能為空",
      "strategy": 'isNonEmpty'
    },
   {
      "erroMsg": "最小為6位",
      "strategy": 'minLength:6'
    }
])

將策略用數(shù)組的方式傳入validator對象里,緩存在this.cache里,只需要調(diào)整對應的add方法就可以

//old type
Validator.prototype.add = function(item,rule,erroMsg){
  var arg = rule.split(":") // rule= >  "isEmpty" => ["isEmpty"] ||  "minLength:5"=> ["minlength", “5”];
  this.cache.push(function(){
      var strategy = arg.shift();  // =>"isEmpty" || minLength
      arg.unshift(item.value);  //[value] || [value,5]
      arg.push(errMsg)// [value,errMsg] || [value,5,errMsg]
      return  stratigies[strategy].apply(item,arg)
  })
}
// new Type
Validator.prototype.add = function(item,rules){
   var  _this = this; //保存this指針   for循環(huán)里的的自執(zhí)行函數(shù)的this指向window,用_this修復指針
  //遍歷rules
 for(var i = 0;i<rules.length;i++){
    var rule = rules[i];
    (function(rule ){
       var arg = rule.strategy.split(":") // rule= >  "isEmpty" => ["isEmpty"] ||  "minLength:5"=> ["minlength", “5”];
       var  errMsg = rule.errMsg;
      _this.cache.push(function(){
            var strategy = arg.shift();  // =>"isEmpty" || minLength
            arg.unshift(item.value);  //[value] || [value,5]
            arg.push(errMsg)// [value,errMsg] || [value,5,errMsg]
            return  stratigies[strategy].apply(item,arg)
         })
      })(rule)
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 單例模式 適用場景:可能會在場景中使用到對象,但只有一個實例,加載時并不主動創(chuàng)建,需要時才創(chuàng)建 最常見的單例模式,...
    Obeing閱讀 2,311評論 1 10
  • 工廠模式類似于現(xiàn)實生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實現(xiàn)同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 8,116評論 2 17
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內(nèi)部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,637評論 18 399
  • 三、閉包和高階函數(shù) 3.1 閉包 3.1.1 變量的作用域 所謂變量的作用域,就是變量的有效范圍。通過作用域的劃分...
    梁同學de自言自語閱讀 1,551評論 0 6
  • (1) 女生:親愛的,我感冒了。 男生:喝點熱水就好了。 女生:我來姨媽了。 男生:喝點熱水就好了。 女生:我胃疼...
    自愈學院閱讀 1,097評論 0 0

友情鏈接更多精彩內(nèi)容