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

什么是策略?

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

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

相关推荐
曼巴UE57 小时前
UE FString, FName ,FText 三者转换,再次学习,官方文档理解
服务器·前端·javascript
行走的陀螺仪8 小时前
高级前端 Input 公共组件设计方案(Vue3 + TypeScript)
前端·javascript·typescript·vue·组件设计方案
一颗不甘坠落的流星8 小时前
【Antd】基于 Upload 组件,导入Json文件并转换为Json数据
前端·javascript·json
LYFlied9 小时前
Vue2 与 Vue3 虚拟DOM更新原理深度解析
前端·javascript·vue.js·虚拟dom
Lucky_Turtle9 小时前
【Node】npm install报错npm error Cannot read properties of null (reading ‘matches‘)
前端·npm·node.js
小飞侠在吗9 小时前
vue shallowRef 与 shallowReacitive
前端·javascript·vue.js
惜分飞9 小时前
sql server 事务日志备份异常恢复案例---惜分飞
前端·数据库·php
GISer_Jing10 小时前
WebGL实例化渲染:性能提升策略
前端·javascript·webgl
烟锁池塘柳010 小时前
【技术栈-前端】告别“转圈圈”:详解前端性能优化之“乐观 UI” (Optimistic UI)
前端·ui