策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换

使用策略模式计算奖金

策略模式有着广泛的应用。本节我们就以年终奖的计算为例进行介绍。

很多公司的年终奖是根据员工的工资基数和年底绩效情况来发放的。例如,绩效为 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

  1. <a name="u0yji"></a>
  2. #### 使用组合函数重构代码
  3. ```javascript
  4. var performanceS = function(salary){
  5. return salary * 4
  6. }
  7. var performanceA = function(salary){
  8. return salary * 3
  9. }
  10. var performanceB = function(salary){
  11. return salary * 2
  12. }
  13. var calculateBonus = function (level, salary) {
  14. if (level === 's') {
  15. return performanceS(salary)
  16. }
  17. if (level === 'a') {
  18. return performanceA(salary)
  19. }
  20. if (level === 'b') {
  21. return performanceB(salary)
  22. }
  23. }
  • calculateBonus 函数有可能越来越庞大,而且在系统变化的时候缺乏弹性

策略模式实现

  1. var PerformanceS = function () {}
  2. performanceS.prototype.calculate = function (salary) {
  3. return salary * 4
  4. }
  5. var performanceA = function () {}
  6. performanceA.prototype.calculate = function (salary) {
  7. return salary * 3
  8. }
  9. var performanceB = function () {}
  10. performanceB.prototype.calculate = function (salary) {
  11. return salary * 2
  12. }
  13. // 接下来定义奖金类
  14. var Bonus = function () {
  15. this.salary = null // 原始工资
  16. this.strategy = null // 绩效工资对应的策略对象
  17. }
  18. Bonus.prototype.setSalary = function (salary) {
  19. this.salary = salary // 设置原始工资
  20. }
  21. Bonus.prototype.setStrategy = function (strategy) {
  22. this.strategy = strategy // 绩效工资对应的策略对象
  23. }
  24. Bonus.prototype.getBonus = function () {
  25. return this.strategy.calculate(this.salary) // 把计算奖金的操作,委托给策略对象
  26. // 。。。。有一点java抽象类的概念,需要strategy必须实现calculate方法
  27. }

JavaScript中的策略模式

  1. var strategies = {
  2. S: function (salary) {
  3. return salary * 4
  4. },
  5. A: function (salary) {
  6. return salary * 3
  7. },
  8. B: function (salary) {
  9. return salary * 2
  10. },
  11. }
  12. var calculateBonus = function (level, salary) {
  13. return strategies[level](salary)
  14. }
  15. console.log(calculateBonus('S', 20000))

表单验证

  • 原始代码

    1. var registerForm = document.getElementById('registerForm')
    2. registerForm.onsubmit = function () {
    3. if (registerForm.userName.value === '') {
    4. alert('用户名不能为空')
    5. return false
    6. }
    7. if (registerForm.password.value.length < 6) {
    8. alert('密码长度不能少于 6 位')
    9. return false
    10. }
    11. if (!/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value)) {
    12. alert('手机号码格式不正确')
    13. return false
    14. }
    15. }

    优化后代码
  • 规则

    1. var strategies = {
    2. isNonEmpty: function (value, errorMsg) {
    3. // 不为空
    4. if (value === '') {
    5. return errorMsg
    6. }
    7. },
    8. minLength: function (value, length, errorMsg) {
    9. // 限制最小长度
    10. if (value.length < length) {
    11. return errorMsg
    12. }
    13. },
    14. isMobile: function (value, errorMsg) {
    15. // 手机号码格式
    16. if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
    17. return errorMsg
    18. }
    19. },
    20. }
  • 验证对象 ```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 } } }

  1. - 用法
  2. ```javascript
  3. var validataFunc = function () {
  4. var validator = new Validator() // 创建一个 validator 对象
  5. /***************添加一些校验规则****************/
  6. validator.add(registerForm.userName, 'isNonEmpty', '用户名不能为空')
  7. validator.add(registerForm.password, 'minLength:6', '密码长度不能少于 6 位')
  8. validator.add(registerForm.phoneNumber, 'isMobile', '手机号码格式不正确')
  9. var errorMsg = validator.start() // 获得校验结果
  10. return errorMsg // 返回校验结果
  11. }
  12. var registerForm = document.getElementById('registerForm')
  13. registerForm.onsubmit = function () {
  14. var errorMsg = validataFunc() // 如果 errorMsg 有确切的返回值,说明未通过校验
  15. if (errorMsg) {
  16. alert(errorMsg)
  17. return false // 阻止表单提交
  18. }
  19. }