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

什么是策略?

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

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

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

js 复制代码
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;
}

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

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

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

什么是策略模式?

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

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

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

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

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

优化思路:

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

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

js 复制代码
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;
      }
    }
  }
}

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

js 复制代码
// 校验逻辑,返回值为错误信息,无返回值表示校验通过
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();
}

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

总结

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

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

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

参考

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

Strategy pattern

A Beginner's Guide to the Strategy Design Pattern

Strategy

相关推荐
一袋米扛几楼989 分钟前
【Git】规范化协作:详解 GitHub 工作流中的 Issue、Branch 与 Pull Request 最佳实践
前端·git·github·issue
网络点点滴23 分钟前
前端与后端的区别与联系
前端
EnCi Zheng1 小时前
M5-markconv自定义CSS样式指南 [特殊字符]
前端·css·python
kyriewen1 小时前
你的网页慢,用户不说直接走——前端性能监控教你“读心术”
前端·性能优化·监控
广州华水科技1 小时前
北斗GNSS变形监测在大坝安全监测中的应用与优势分析
前端
前端老石人1 小时前
前端开发中的 URL 完全指南
开发语言·前端·javascript·css·html
CAE虚拟与现实1 小时前
五一假期闲来无事,来个前段、后端的说明吧
前端·后端·vtk·three.js·前后端
Sarvartha1 小时前
三目运算符
linux·服务器·前端
晓晨的博客1 小时前
ROS1录制的bag包转换为ROS2格式
前端·chrome
Wect1 小时前
LeetCode 72. 编辑距离:动态规划经典题解
前端·算法·typescript