策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换
使用策略模式计算奖金
策略模式有着广泛的应用。本节我们就以年终奖的计算为例进行介绍。
很多公司的年终奖是根据员工的工资基数和年底绩效情况来发放的。例如,绩效为 S 的人年 终奖有 4 倍工资,绩效为 A 的人年终奖有 3 倍工资,而绩效为 B 的人年终奖是 2 倍工资。假设财 务部要求我们提供一段代码,来方便他们计算员工的年终奖。
if…else…
- 这个代码很简单,但是会包含很多的if…else…
- 代码复用性很差
代码
```javascript var calculateBonus = function (level, salary) { if (level === ‘s’) { return salary 4 } if (level === ‘a’) { return salary 3 } if (level === ‘b’) { return salary * 2 } }
calculateBonus(‘s’, 20000) // 80000 calculateBonus(‘b’, 10000) // 20000
<a name="u0yji"></a>#### 使用组合函数重构代码```javascriptvar performanceS = function(salary){return salary * 4}var performanceA = function(salary){return salary * 3}var performanceB = function(salary){return salary * 2}var calculateBonus = function (level, salary) {if (level === 's') {return performanceS(salary)}if (level === 'a') {return performanceA(salary)}if (level === 'b') {return performanceB(salary)}}
- calculateBonus 函数有可能越来越庞大,而且在系统变化的时候缺乏弹性
策略模式实现
var PerformanceS = function () {}performanceS.prototype.calculate = function (salary) {return salary * 4}var performanceA = function () {}performanceA.prototype.calculate = function (salary) {return salary * 3}var performanceB = function () {}performanceB.prototype.calculate = function (salary) {return salary * 2}// 接下来定义奖金类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.calculate(this.salary) // 把计算奖金的操作,委托给策略对象// 。。。。有一点java抽象类的概念,需要strategy必须实现calculate方法}
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', 20000))
表单验证
原始代码
var registerForm = document.getElementById('registerForm')registerForm.onsubmit = function () {if (registerForm.userName.value === '') {alert('用户名不能为空')return false}if (registerForm.password.value.length < 6) {alert('密码长度不能少于 6 位')return false}if (!/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value)) {alert('手机号码格式不正确')return false}}
优化后代码
规则
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}},}
验证对象 ```javascript 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, validataFunc; (validataFunc = this.cache[i++]); ) { var msg = validataFunc() if (msg) { return msg } } }
- 用法```javascriptvar validataFunc = function () {var validator = new Validator() // 创建一个 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() // 如果 errorMsg 有确切的返回值,说明未通过校验if (errorMsg) {alert(errorMsg)return false // 阻止表单提交}}
