策略模式的定義是: 定義一系列的算法,把它們一個個封裝起來,而且是它們能夠相互替換。
此文僅記錄本人閱讀《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中能夠將一個個策略類寫成函數,而後封裝在對象中:算法
// 計算獎金的例子 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