什麼是策略模式,官方定義是:定義一些列算法,把他們封裝起來,而且能夠相互替換。說人話(⊙ˍ⊙):就是把看似毫無聯繫的代碼提取封裝、複用,使之更容易被理解和拓展。常見的用於一次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對象的屬性,就能自定義本身的驗證規則,而且能夠複用,大大方便了平常開發!算法