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

什么是策略?

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

举个栗子:我要实现一个表单校验功能,要求 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

相关推荐
咖喱鱼蛋1 分钟前
Electron一些概念理解
前端·javascript·electron
yqcoder3 分钟前
Vue3 + Vite + Electron + TS 项目构建
前端·javascript·vue.js
鑫宝Code20 分钟前
【React】React Router:深入理解前端路由的工作原理
前端·react.js·前端框架
Mr_Xuhhh2 小时前
重生之我在学环境变量
linux·运维·服务器·前端·chrome·算法
永乐春秋2 小时前
WEB攻防-通用漏洞&文件上传&js验证&mime&user.ini&语言特性
前端
鸽鸽程序猿2 小时前
【前端】CSS
前端·css
ggdpzhk2 小时前
VUE:基于MVVN的前端js框架
前端·javascript·vue.js
学不会•5 小时前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
哪 吒5 小时前
最简单的设计模式,抽象工厂模式,是否属于过度设计?
设计模式·抽象工厂模式
Theodore_10225 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee