javascript设计模式-策略模式

在我最近的一个项目中,有一个模块是关于表单校验的需求,需求大致是验证输入不能空不能够重复的字符串等等,检验的规则大概有10种,而我的同事为了检验这样的表单功能,则编写大量的if-else代码,伪代码如下:

if (value.length ===0) {
      // todo
    } else if (value.length < 6) {
      //todo
    } else if (.....) {
      //todo
    }

可以发现上面的代码十分简单,也非常实用,但是也存在明显的缺点:

  1. 包含了大量的if-else语句,这些语句覆盖了大量的逻辑。
  2. 上述代码缺乏弹性,如果增加了新的需求,则必须重复的添加else if。
  3. 逻辑的复用性很差,我如果是其它的模块也操作相似的逻辑,则必须全部都复制一遍过去,造成一种很臃肿和很恶心的代码。
    为了解决以上存在的问题,我们就很自然联想到设计模式中的一种-策略模式:
    策略模式的定义:

定义一系列的算法,把他们一个个封装起来,并且使它们可以相互替换。

又比如我们现在有如下的场景:

如果绩效为S的人,那么他的年终奖则是他工资的4倍,如果绩效为A的人,那么他的年终奖则是他工资的3倍,如果绩效为B的人,那么他的年终奖则是他工资的2倍。

那么我们就自然的想到编写以下的代码:

	let calculateBonus = (level,salary)=>{
      if (level === "S") {
        return salary*4
      }else if (level === "A") {
        return salary*3
      }else if (level === "B"){
        return salary * 2
      }
    }
    console.log(calculateBonus("A",200)) // 800
    console.log(calculateBonus("B",200)) // 600

那么其实这种代码,在某种程度上来,看着是很蠢的,也不符合,现在前端高大上,逼格高的作风。所以我们需要把它给改造一下:

let strategies = {
      "S": function (salary) {
        return salary * 4
      },
      "A": function (salary) {
        return salary * 3
      },
      "B": function (salary) {
        return salary * 2
      }
    }
    let calcteBonus = (level, salary) => {
      return strategies[level](salary);
    }
    console.log(calcteBonus("S", 200)) // 800
    console.log(calculateBonus("B", 200)) // 600

上面的代码,我们通过构造strategies 对象,来存放各个逻辑的函数。实际上在javascript语言中,函数也是对象,函数也可以作为value来输出。
通过以上的改造,我们可以看到代码的结构更加简洁了,else-if的语句也不存在了,瞬间感觉B格就高了很多。当然了,也不是说else-if不好,只是我们有更好实现这种需求的方式,应当选择更为简洁和聪明的方式,也方便日后的维护。

改造表单验证的代码:
我们回到一开始的表单需求,我们放弃大量elseif的方式,从而采用更为简洁和聪明的形式。假设我们现在有以下的需求为:

  1. 用户名不能为空
  2. 密码长度不能少于6位
  3. 手机号码必须符合格式
<body>
  <form>
    <p>
      用户名:<input type="text" id="username">
    </p>
    <p>
      密码:<input type="text" id="password">
    </p>
    <p>
      电话:<input type="text" id="telphone">
    </p>
    <p>
      <button id="btn" type="button">按钮</button>
    </p>
  </form>
  <script>
    var oBtn = document.getElementById("btn");
    var oUserName = document.getElementById("username");
    var oPassword = document.getElementById("password");
    var oTelphone = document.getElementById("telphone");
    oBtn.onclick = function () {
      if (oUserName.value === "") {
        alert("输入不能为空");
        return false;
      }
      if (oPassword.value.length < 6) {
        alert("密码不能少于6位");
        return false;
      }
      if (!/(^1[3|5|8[0-9]{9}]$)/.test(oTelphone.value)) {
        alert("手机号码格式不正确!");
        return false;
      }
    }
  </script>
</body>

我们又自然就编写以上的代码,这样我们又无法避免写出了大量if-else的代码。所以,我们又需要把代码进行重构!

<body>
  <form>
    <p>
      用户名:<input type="text" id="username">
    </p>
    <p>
      密码:<input type="text" id="password">
    </p>
    <p>
      电话:<input type="text" id="telphone">
    </p>
    <p>
      <button id="btn" type="button">按钮</button>
    </p>
  </form>
  <script>
    let oBtn = document.getElementById("btn");
    let oUserName = document.getElementById("username");
    let oPassword = document.getElementById("password");
    let oTelphone = document.getElementById("telphone");
    //校验规则的对象
    let strategies = {
      isNoEmpty: function (value, msg) {
        if (value.length === 0) {
          return msg;
        }
      },
      minLength: function (value, length, msg) {
        if (value.length < length) {
          return msg;
        }
      },
      isMobile: function (value, msg) {
        if (!/(^1[3|5|8[0-9]{9}]$)/.test(value)) {
          return msg;
        }
      }
    }
    // 构造检验类
    let validataFun = function () {
      var validator = new Validator();
      // 添加检验规则
      validator.add(oUserName, "isNoEmpty", "用户名不能为空!");
      validator.add(oPassword, "minLength:6", "密码长度不能小于6!");
      validator.add(oTelphone, "isMobile", "手机号码格式不正确!");
      let msg = validator.start(); // 调用开始检验的方法
      return msg;
    }
    function Validator() {
      this.cache = []; // 保存检验规则的数组
    }
    // 通过原型挂载add方法
    Validator.prototype.add = function (dom, rule, msg) {
      let ary = rule.split(":");
      this.cache.push(function () { // 把检验的函数push进数组
        let strategy = ary.shift(); // 用户所操作的strategy,删除第一项的数据,并返回第一项的数据
        ary.unshift(dom.value); // unshift向开头添加元素,会影响到原数组
        ary.push(msg);
        return strategies[strategy](...ary);
        // return strategies[strategy].apply(dom, ary);
      })
    }
    // 执行检验规则
    Validator.prototype.start = function () {
      // console.log(this.cache[0]());
      for (let i = 0; i < this.cache.length; i++) {
        let msg = this.cache[i]();
        if (msg) {
          return msg;
        }
      }
    }

    oBtn.onclick = function () {
      let msg = validataFun();
      if (msg) {
        alert(msg); // 输出失败检验的信息
        return false;
      }
    }
  </script>
</body>

我们通过策略模式重构代码后,我们发现可以通过配置方式来改变,某一个input的检验规则,例如,我们把用户名输入不能少于10个字符,则可以把代码修改为:

validator.add(oUserName, "minLength:10", "用户名长度不能小于10!");

那么问题来了,我希望用户名不能为空的同时,还希望它的长度不能少于6位,那么上面的代码则又需要进行修改。我们期望的是按照以下的检验规则来进行校验:

validator.add(oUserName, [{
        strategy: "isNoEmpty",
        msg: "用户名不能为空!"
      }, {
        strategy: "minLength:6",
        msg: "用户名不能少于6位!"
      }])
      validator.add(oPassword, "minLength:6", "密码长度不能小于6!");
      validator.add(oTelphone, "isMobile", "手机号码格式不正确!");

这个时候add方法,第二个参数接受的是数组,那么我们就通过遍历这个数组,把检验规则都push进cache数组中。

<body>
  <form>
    <p>
      用户名:<input type="text" id="username">
    </p>
    <p>
      密码:<input type="text" id="password">
    </p>
    <p>
      电话:<input type="text" id="telphone">
    </p>
    <p>
      <button id="btn" type="button">按钮</button>
    </p>
  </form>
  <script>
    let oBtn = document.getElementById("btn");
    let oUserName = document.getElementById("username");
    let oPassword = document.getElementById("password");
    let oTelphone = document.getElementById("telphone");
    //校验规则的对象
    let strategies = {
      isNoEmpty: function (value, msg) {
        if (value.length === 0) {
          return msg;
        }
      },
      minLength: function (value, length, msg) {
        if (value.length < length) {
          return msg;
        }
      },
      isMobile: function (value, msg) {
        if (!/(^1[3|5|8[0-9]{9}]$)/.test(value)) {
          return msg;
        }
      }
    }
    // 构造检验类
    let validataFun = function () {
      var validator = new Validator();
      // 添加检验规则
      // validator.add(oUserName, "isNoEmpty", "用户名不能为空!");
      // validator.add(oPassword, "minLength:6", "密码长度不能小于6!");
      // validator.add(oTelphone, "isMobile", "手机号码格式不正确!");
      validator.add(oUserName, [{
        strategy: "isNoEmpty",
        msg: "用户名不能为空!"
      }, {
        strategy: "minLength:6",
        msg: "用户名不能少于6位!"
      }])
      validator.add(oPassword, [{
        strategy: "minLength:6",
        msg: "密码不能少于6位"
      }]);
      validator.add(oTelphone, [{
        strategy: "isMobile",
        msg: "校验规则不正确!"
      }]);
      let msg = validator.start(); // 调用开始检验的方法
      return msg;
    }

    function Validator() {
      this.cache = []; // 保存检验规则的数组
    }
    // 通过原型挂载add方法
    Validator.prototype.add = function (dom, rule, msg) {
      for (let i = 0; i < rule.length; i++) {
        let ary = rule[i].strategy.split(":");
        this.cache.push(function () { // 把检验的函数push进数组
          let strategy = ary.shift(); // 用户所操作的strategy,删除第一项的数据,并返回第一项的数据
          ary.unshift(dom.value); // unshift向开头添加元素,会影响到原数组
          ary.push(rule[i].msg);
          return strategies[strategy](...ary);
          // return strategies[strategy].apply(dom, ary);
        })
      }

    }
    // 执行检验规则
    Validator.prototype.start = function () {
      for (let i = 0; i < this.cache.length; i++) {
        let msg = this.cache[i]();
        console.log(msg);
        if (msg) {
          return msg;
        }
      }
    }

    oBtn.onclick = function () {
      let msg = validataFun();
      if (msg) {
        alert(msg); // 输出失败检验的信息
        return false;
      }
    }
  </script>
</body>

通过策略模式,我们是可以很轻松去解决我们日常工作一些比较繁琐的逻辑,当你的代码,产生了大量的if-else语法的时候,可以尝试使用策略模式,那么你的代码就变得简洁和有B格。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip
毕设新项目基于python3.7+django+sqlite开发的学生就业管理系统源码+使用说明(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 学生就业管理系统(前端) ## 项目开发环境 - IDE: vscode - node版本: v12.14.1 - npm版本: 6.13.4 - vue版本: @vue/cli 4.1.2 - 操作系统: UOS 20 ## 1.进入项目目录安装依赖 ``` npm install ``` ## 2.命令行执行进入UI界面进行项目管理 ``` vue ui ``` ## 3.编译发布包(请注意编译后存储路径) #### PS:需要将编译后的包复制到后端项目的根目录下并命名为'static' 学生就业管理系统(后端) ## 1.项目开发环境 - IDE: vscode - Django版本: 3.0.3 - Python版本: python3.7.3 - 数据库 : sqlite3(测试专用) - 操作系统 : UOS 20 ## 2.csdn下载本项目并生成/安装依赖 ``` pip freeze > requirements.txt pip install -r requirements.txt ``` ## 3.项目MySQL数据库链接错误 [点击查看解决方法](https://www.cnblogs.com/izbw/p/11279237.html)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值