• 【设计模式】使用策略模式优化表单校验逻辑


    什么是策略?

    所谓策略,就是根据已知条件决定要做出怎样的行为。

    举个栗子:我要实现一个表单校验功能,要求 name 不能为空且长度必须大于 2 且小于 4,age 不能为空且必须为纯数字。

    这样的判断逻辑直接用 if-else 就可以实现:

    function valid() {
      // 表单校验逻辑
      if (!form.name) {
        alert("name 不能为空");
        return false;
      }
    
      if (form.name.length < 2) {
        alert("name 长度必须大于 2 ");
        return false;
      }
    
      if (form.name.length > 4) {
        alert("name 长度必须小于 4");
        return false;
      }
    
      if (!form.age) {
        alert("age 不能为空");
        return false;
      }
    
      if (!/^\d+$/.test(form.age)) {
        alert("age 只能为数字");
        return false;
      }
    
      return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    这种实现方式有几个缺点:

    • 最终实现的 valid() 函数比较庞大,并且包含了很多 if-else 语句,需要在这里覆盖所有的校验规则。
    • 算法复用性差,如果其他地方也要进行类似的校验,就需要将这些校验逻辑到处复制粘贴。

    策略模式就是为了解决这些问题而生的。

    什么是策略模式?

    策略模式的核心思想是将算法与使用对象分开,对象不是直接实现单个算法,而是在执行时决定要使用哪些算法。

    它基于组合优于继承的原则,通过对一系列算法的封装,使它们在运行时可以互换。

    这使得对象更加灵活和可重用,因为可以轻松添加或修改不同的策略,而无需更改对象的核心代码。

    以上面的表单校验逻辑为例,这段代码中有四个策略: 字段不能为空字段长度必须大于x字段长度必须小于x字段只能为数字

    用策略模式优化表单校验逻辑

    优化思路:

    1. 隔离校验逻辑。
    2. 封装校验类,统一管理校验逻辑。

    Validator 类中封装所有校验策略,并提供通用的使用接口。

    class Validator {
      /**
       * 内置校验策略
       */
      static strategy = {
        require(value, errorMsg) {
          if (value === "" || value === undefined || value === null) {
            return errorMsg;
          }
        },
        minLength(value, errorMsg, length) {
          if (value.length < length) {
            return errorMsg;
          }
        },
        maxLength(value, errorMsg, length) {
          if (value.length > length) {
            return errorMsg;
          }
        },
        number(value, errorMsg) {
          if (!/^\d+$/.test(value)) {
            return errorMsg;
          }
        },
      };
    
      rules = [];
    
      /**
       * 添加一条校验规则
       * @param {*} value 待校验的值
       * @param {*} validFn 校验方法
       * @param {*} errorMsg 错误信息
       */
      add(value, validFn, errorMsg, ...args) {
        if (typeof validFn === "function") {
          this.rules.push(validFn.bind(this, value, errorMsg, ...args));
        } else {
          console.error("validFn 必须是一个函数");
        }
      }
    
      /**
       * 启动校验
       */
      valid() {
        let length = this.rules.length;
        while (length--) {
          const rule = this.rules.shift();
          const errorMsg = rule();
          if (errorMsg) {
            return errorMsg;
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    业务逻辑中的使用方式如下:

    // 校验逻辑,返回值为错误信息,无返回值表示校验通过
    function valid() {
      const validator = new Validator();
      // 给 name 设置校验规则
      validator.add(form.name, Validator.strategy.require, "name 不能为空");
      validator.add(
        form.name,
        Validator.strategy.minLength,
        "name 长度必须大于 2",
        2
      );
      validator.add(
        form.name,
        Validator.strategy.maxLength,
        "name 长度必须小于 4",
        4
      );
    
      validator.add(form.age, Validator.strategy.require, "age 不能为空");
      validator.add(form.age, Validator.strategy.number, "age 只能为数字");
    
      // 校验
      return validator.valid();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    使用策略模式重构表单校验逻辑后,可以通过配置的方式就完成一个表单的校验,这些校验规则也可以更方便的复用。

    总结

    策略模式的优点是提高代码的灵活性和可复用性。

    它的缺点是使用者必须了解所有的策略,才能选择合适的策略。

    如果逻辑比较简单,使用 if-else 足以应对,就没必要用策略模式。

    参考

    《JavaScript 设计模式与开发实践》

    Strategy pattern

    A Beginner’s Guide to the Strategy Design Pattern

    Strategy

  • 相关阅读:
    面试官:transient关键字修饰的变量当真不可序列化?我:烦请先生教我!
    【ESP32_8266_WiFi (八)】Stream
    面试:换肤方案
    java 线上java应用CPU过高排查
    EasyExcel复杂表头导出(一对多)
    Grafana系列-GaC-1-Grafana即代码的几种实现方式
    数据结构——排序算法——堆排序
    Centos MySQL --skip-grant-tables详解
    自动驾驶,从“宠儿”走进“淘汰赛”
    Go 语言 设计模式-单例模式
  • 原文地址:https://blog.csdn.net/qq_37012965/article/details/138195848