深刻淺出js中的策略模式

什麼是策略模式,官方定義是:定義一些列算法,把他們封裝起來,而且能夠相互替換。說人話(⊙ˍ⊙):就是把看似毫無聯繫的代碼提取封裝、複用,使之更容易被理解和拓展。常見的用於一次if判斷、switch枚舉、數據字典等流程判斷語句中。html

使用策略模式計算等級

在遊戲中,咱們每玩完一局遊戲都有對用戶進行等級評價,好比S級4倍經驗,A級3倍經驗,B級2倍經驗,其餘1倍經驗,用函數來表達以下:vue

function getExperience(level, experience){
      if(level == 'S'){
        return 4*experience
      }
      if(level == 'A'){
        return 3*experience
      }
      if(level == 'B'){
        return 2*experience
      }
      return experience
    }

可知getExperience函數各類if條件判斷,複用性差,咱們根據策略模式封裝複用的思想,進行改寫。node

// 改成策略模式 分紅兩個函數來寫
    const strategy = {
      'S' : function(experience){
        return 4*experience
      },
      'A' : function(experience){
        return 3*experience
      },
      'B' : function(experience){
        return 2*experience
      }
    }
    // getExperience能夠複用
    function getExperience(strategy, level, experience){
      return (level in strategy) ? strategy[level](experience) : experience
    }
    var s = getExperience(strategy, 'S', 100)
    var a = getExperience(strategy, 'A', 100)
    console.log(s, a) // 400 300

分爲兩個函數以後,strategy對象解耦,拓展性強。在vue數據驅動視圖更新的更新器updater使用,就使用了策略模式。想要進一步瞭解vue底層原理,能夠參考能夠參考github上的一篇文章 ☛ MVVM實現git

// 指令處理集合
var compileUtil = {
    // v-text更新視圖原理
    text: function(node, vm, exp) {
        this.bind(node, vm, exp, 'text');
    },
    // v-html更新視圖原理
    html: function(node, vm, exp) {
        this.bind(node, vm, exp, 'html');
    },
    // v-class綁定原理
    class: function(node, vm, exp) {
        this.bind(node, vm, exp, 'class');
    },
    bind: function(node, vm, exp, dir) {
        // 不一樣指令觸發視圖更新
        var updaterFn = updater[dir + 'Updater'];
        updaterFn && updaterFn(node, this._getVMVal(vm, exp));
        new Watcher(vm, exp, function(value, oldValue) {
            updaterFn && updaterFn(node, value, oldValue);
        });
    }
    ......
}

使用策略模式驗證表單

常見表單驗證用if、else流程語句判斷用戶輸入數據是否符合驗證規則,而在Elementui中,基於async-validator庫,只須要經過rule屬性傳入約定的驗證規則,便可校驗。方便快捷,可複用。如今咱們根據策略模式仿寫一個校驗方式。github

// 咱們寫一個form表單
    <form action="/" class="form">
      <input type="text" name="username">
      <input type="password" name="password"> 
      <button>submit</button>
    </form>
    <div id="tip"></div>
  • 首先定義校驗規則
const strategies = {
      // 非空
      noEmpty: function(value, errMsg){
        if(value === ''){
          return errMsg
        }
      },
      // 最小長度
      minLength: function(value, length, errMsg){
        if(!value || value.length < length){
          return errMsg
        }
      },
      // 最大長度
      maxLength: function(value, length, errMsg){
        if(value.length > length){
          return errMsg
        }
      }
    }
  • 接着設置驗證器
// 建立驗證器
    var Validator = function(strategies){
      this.strategies = strategies
      this.cache = [] // 存儲校驗規則
    }
    // 添加校驗規則
    Validator.prototype.add = function(dom, rules){
      rules.forEach(item => {
        this.cache.push(() => {
          let value = dom.value
          let arr = item.rule.split(':')
          let name = arr.shift()
          let params = [value, ...arr, item.errMsg]
          // apply保證上下文一致
          return this.strategies[name].apply(dom, params)
        })
      })
    }
    // 校驗結果
    Validator.prototype.validate = function(dom, rules, errMsg){
      // 遍歷cache裏面的校驗函數
      for(let i = 0, validateFun; validateFun = this.cache[i++];){
        const message = validateFun()
        // 返回報錯信息,終止驗證並拋出異常
        if(message) return message
      }
    }
  • 最後進行校驗
var form = document.querySelector("form")
    // 提交表單
    form.onsubmit = function(event){
      event.preventDefault() 
      // 判斷驗證結果
      const message = validate()
      const tip = document.getElementById('tip')
      if(message){
        tip.innerHTML = message
        tip.style.color = 'red'
      }else{
        tip.innerHTML = '驗證經過!'
        tip.style.color = 'green'
      }
    }
    // 校驗函數
    function validate(){
      // 實例驗證器
      const validator = new Validator(strategies)
      // 添加驗證規則
      validator.add(form.username, [
        {
          rule: 'noEmpty',
          errMsg: '用戶名不能爲空!'
        },
        {
          rule: 'minLength:3',
          errMsg: '用戶名長度大於3!'
        }
      ])
      validator.add(form.password, [
        {
          rule: 'minLength:6',
          errMsg: '密碼長度大於6!'
        },
        {
          rule: 'maxLength:10',
          errMsg: '密碼最大長度爲10!'
        }
      ])
      // 進行校驗,並返回結果
      return validator.validate()
    }

如上所示,咱們只要添加strategies對象的屬性,就能自定義本身的驗證規則,而且能夠複用,大大方便了平常開發!算法

相關文章
相關標籤/搜索