JS策略模式《JavaScript設計模式與開發實踐》閱讀筆記

策略模式的定義是: 定義一系列的算法,把它們一個個封裝起來,而且是它們能夠相互替換
  • 策略模式能夠避免代碼中的多重判斷條件。
  • 策略模式很好的體現了開放-封閉原則,將一個個算法(解決方案)封裝在一個個策略類中。便於切換,理解,擴展。
  • 策略中的各類算法能夠重複利用在系統的各個地方,避免複製粘貼。
  • 策略模式在程序中或多或少的增長了策略類。但比堆砌在業務邏輯中要清晰明瞭。
  • 違反最少知識原則,必需要了解各類策略類,才能更好的在業務中應用。

此文僅記錄本人閱讀《JavaScript設計模式與開發實踐》這個本時的感覺,感謝做者曾探寫出這麼好的一本書。若有冒犯,若有錯誤,請聯繫本人處理。javascript

簡單的業務場景

計算員工年終獎須要根據不一樣的員工績效計算不一樣的獎金。例如,績效爲S的人年終獎有4倍工資。績效A的人年終獎有3倍工資,績效B的人有2倍工資。

用代碼實現:html

var calculateBonus = function(performanceLevel, salary) {
    if (performanceLevel === 'S') {
        return salary * 4
    }
    if (performanceLevel === 'A') {
        return salary * 3
    } 
    if (performanceLevel === 'B') {
        return salary * 2
    }
}

calculateBonus('S', 2000) // 8000
calculateBonus('A', 2000) // 6000

其實上面一段代碼已經能應付目前的場景。可是,當獎金的評定須要增長一個績效C,或者改變績效A的計算方式。此時須要更改上面這個calculateBonus方法的內部結構,如此下去,這個方法內部將變得冗雜。前端

設計模式中很重要的一點就是將不變和變分離出來。這裏變的是怎麼算。不變的是根據一個績效得到一個結果。因此上述代碼重寫,把各類算法封裝在一個個策略類中(傳統面向對象的模仿):java

var performanceS = function() {}
performanceS.prototype.calc = function(salary) {
    return salary * 4
}

var performanceA = function() {}
performanceA.prototype.calc = function(salary) {
    return salary * 3
}

var performanceB = function() {}
performanceB.prototype.calc = function(salary) {
    return salary * 2
}

//獎金類Bonus
var Bonus = function() {
    this.salary = null //原始工資
    this.strategy = null // 績效等級對應的策略對象
}

Bonus.prototype.setSalary = function(salary) {
    this.salary = salary //設置工資
}

Bonus.prototype.setStrategy = function(strategy) {
    this.strategy = strategy //設置員工績效對應的策略對象
}

Bonus.prototype.getBonus = function() { //獲取獎金數額
    return this.strategy.calc(this.salary) //把計算獎金的操做委託個對應的策略對象
}

var bonus = new Bonus()
bonus.setSalary(10000)
bonus.setStrategy(new performanceA())

console.log(bonus.getBonus()) // 30000

JavaScript版本的策略模式

在JavaScript中能夠將一個個策略類寫成函數,而後封裝在對象中:算法

// 計算獎金的例子
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', 10000)) // 40000
console.log(calculateBonus('S', 20000)) // 80000

更廣義的「算法」

策略模式指的是一系列的算法(策略),而且把它們封裝起來。計算獎金的列子中就封裝了一些算法。其實世紀業務中也能夠利用策略模式來封裝一些「業務規則」。後端

表單驗證

在Web項目中每每有不少場景須要提交表單。前端在把數據提交到後端以前,須要進行一波表單驗證,來減小沒必要要的網絡請求。在表單驗證中每每會有多種校驗規則,頁面中可能會有多個表單要進行驗證。此時能夠用策略模式來實現一個表單驗證:設計模式

<form action="" mothod="post" id="registerForm">
  輸入用戶名: <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, rule, errorMsg){
      var ary = rule.split(':')
      this.cache.push(function(){
        var strategy = ary.shift()
        ary.unshift(dom.value)
        ary.push(errorMsg)
        return strategies[ strategy ].apply(dom, ary)
      })
    }

    Validator.prototype.start = function(){
      for (var i = 0,validatorFunc;validatorFunc = this.cache[i++];){
        var msg = validatorFunc()
        if(msg){
          return msg
        }
      }
    }

    var validataFunc = function() {
      var validator = new Validator()
    // 添加校驗規則
      validator.add(registerForm.userName,'isNonEmpty', '用戶名不能爲空')
      validator.add(registerForm.password,'minLength:6', '密碼長度不能少於6位')
      validator.add(registerForm.phoneNumber,'isMobile', '手機格式不正確')

      var errorMsg = validator.start()
      return errorMsg
    }

    var registerForm = document.getElementById('registerForm')
    registerForm.onsubmit = function(){
      var errorMsg = validataFunc()
      if (errorMsg) {
        console.log(errorMsg)
        return false
      }
    }
</script>

總結

  • 在平常開發中一些工具函數能夠封裝在一塊兒,組成本身的工具庫。減小沒必要要的代碼複製粘貼。
  • 感受敲代碼思想更重要啦,這裏策略模式體現了開放-封閉原則下降代碼的耦合度。這些理念都是我本身在敲代碼的路上要慢慢學習和積累的。
  • 敲出來的代碼不能只有本身認識。要多注意細節,時刻去想哪些代碼能夠再多完善。
  • 固然不是全部的東西都要分來分去,一個簡單的需求爲了設計模式而去設計模式也是不可取的。

love & peace網絡

參考

《JavaScript設計模式與開發實踐》—— 曾探app

相關文章
相關標籤/搜索