策略模式在JavaScript中的使用

最近在看《JavaScript设计模式与开发实践》,一本很不错的书,本次内容整理自该书,以便日后翻阅。

在程序设计中,常常遇到类似的情况,要实现某一个功能有多种方案可以选择。比如一个压缩文件的程序,既可以选择zip算法,也可以选择gzip算法。这些算法灵活多样,而且可以随意互相替换。这种解决方案就是本文将要介绍的策略模式。策略模式是指定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。

下面是策略模式运用的两个例子:

1.奖金计算
很多公司的年终奖是根据员工的工资基数和年底绩效情况来发放的。例如,绩效为S的人年终奖有4倍工资,绩效为A的人年终奖有3倍工资,而绩效为B的人年终奖是2倍工资。


var calculateBonus = function( performanceLevel, salary ){
    if ( performanceLevel === 'S' ){
        return salary * 4;
    }
    if ( performanceLevel === 'A' ){
        return salary * 3;
    }
    if ( performanceLevel === 'B' ){
        return salary * 2;
    }
};
calculateBonus( 'B', 20000 ); // 输出:40000
calculateBonus( 'S', 6000 ); // 输出:24000

很多人会使用上面那种方法,看上起也并没有什么问题,但其实还是有些缺点的。缺点:该函数比较庞大,包含了很多if-else语句,这些语句需要覆盖所有的逻辑分支;该函数缺乏弹性,如果增加了一种新的绩效等级C,或者想把绩效S的奖金系数改为5,必须深入calculateBonus函数的内部实现,违反开放封闭原则;算法复用性差,如果在程序其他地方需要重用这些计算奖金的算法,只能选择复制粘贴。

运用策略模式,可以实现得更加优雅,如下:

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 ) ); // 输出:80000
console.log( calculateBonus( 'A', 10000 ) ); // 输出:30000

与前面方法比较,看起来代码量并没有减少,但带来如下改变:消除了那些if else 条件判断语句;如果需要新增一个等级,只需要修改strategies对象一处;复用性更好

2.表单验证

在web项目中,表单验证是比较常见的,后台管理系统尤其多。客户端在把数据提交后台之前常常需要做一些校验,比如注册的时候需要校验是否填写了用户名,密码的长度是否符合规定,等等,这样可以避免因为提交不合法数据而带来的不必要网络开销。

以下图内容为例

假设 字段依次为 title, sort,  port, picture(数组),这些都需要客户端做非空验证,标题还需要最大长度限制为20个字。比较常见的实现方式:

if (title === '') {
  alert('标题不能为空')
  return
}
if (sort === '') {
  alert('序号不能为空')
  return
}
if (port === '') {
  alert('请选择端口')
  return
}
if (!picture.length) {
  alert('请上传图片')
  return
}

运用策略模式实现:

//validator.js

const strategies = {
  isNonEmpty: function(value, errorMsg) {
    if ( value === '' || value === undefined || value === null || (Array.isArray(value) && !value.length)) {
      return errorMsg
    }
  },
  maxLength: function(value, length, errorMsg) {
    if ( value.length > length) {
      return errorMsg
    }
  }
}

const Validator = function() {
  this.cache = [];
};

Validator.prototype.add = function(value, rules) {
  let  self = this;
  for ( let i = 0, rule; rule = rules[i++];) {
    (function(rule) {
      let strategyAry = rule.strategy.split(':');
      let errorMsg = rule.errorMsg;
      self.cache.push(function() {
        let strategy = strategyAry.shift();
        strategyAry.unshift(value);
        strategyAry.push(errorMsg);
        return strategies[strategy].apply(value, strategyAry);
      })
    })(rule)
  }
}

Validator.prototype.start = function() {
  for (let i = 0, validatorFunc; validatorFunc = this.cache[i++];) {
    let errorMsg  = validatorFunc();
    if (errorMsg) {
       return  errorMsg
    }
  } 
}

export default Validator;

//页面调用
import Validator from 'validator.js文件路径';

let validator = new Validator();
      validator.add(title, [{
        strategy: 'isNonEmpty',
        errorMsg: '标题不能为空'
      },{
        strategy: 'maxLength:20',
        errorMsg: '标题不能超过20个字'
      }])
      validator.add(indexNum, [{
        strategy: 'isNonEmpty',
        errorMsg: '权重不能为空'
      }])
      validator.add(port, [{
        strategy: 'isNonEmpty',
        errorMsg: '请选择展示端口'
      }])
      validator.add(this.picture, [{
        strategy: 'isNonEmpty',
        errorMsg: '请上传图片'
      }])
      let errorMsg = validator.start();
      if (errorMsg) {
        this.$message(errorMsg);
        return;
      }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值