利用策略模式重构前端表单校验逻辑

作者:小括号时间:2026-10-25 12:50:21浏览:261

本文通过注册页面表单校验案例,分析传统if-else写法在维护性和复用性上的缺陷。引入策略模式,将校验规则封装为独立算法,通过环境类Context统一调度,实现校验逻辑的灵活配置与复用,有效避免多重条件判断,提升代码的可扩展性与可维护性。

前端表单校验

背景

设想开发注册页面,点击注册按钮时触发以下校验逻辑:

  • 用户名字段禁止为空
  • 密码字符数需大于等于6
  • 手机号需匹配正则格式

传统实现方式:

const form = document.getElementById('registerForm');
form.onsubmit = function () {
  if (form.userName.value === '') {
    alert('用户名不能为空');
    return false;
  }
  if (form.password.value.length < 6) {
    alert('密码长度不能少于6位');
    return false;
  }
  if (!/^1[3|5|8][0-9]{9}$/.test(form.phoneNumber.value)) {
    alert('手机号码格式不正确');
    return false;
  }
  ...
}

此编码范式存在显著弊端:

  • onsubmit 函数体积庞大,充斥大量 if-else 分支,需覆盖所有校验场景。
  • onsubmit 函数扩展性差,新增校验规则或修改密码长度阈值(如6改8)需修改函数内部,违背开放-封闭原则。
  • 代码复用率低,若其他表单需类似校验,需复制大量校验逻辑至各处。

如何规避上述缺陷,以更佳方式实现表单校验?

策略模式解析

💡 策略模式属行为设计模式,旨在定义一系列算法,封装各自并支持相互替换。

现实场景类比

前端表单校验

图片引用自 https://www.jb51.net/article/252304.htm

假设需前往机场,可选骑行、乘大巴或打车。这三种出行方案即广义“算法”,均能实现从家至机场的目标。无需知晓内部实现(如大巴驾驶、公路连通性),仅需知晓各方案耗时与费用,即可依据预算时间选择。

广义“算法”定义

开发中常扩展算法含义,使策略模式用于封装“业务规则”。若业务规则目标一致且可替换,即可应用策略模式。

策略模式构成

策略模式至少包含两部分。

第一部分为策略类集合,封装具体算法并负责计算。

第二部分为环境类 Context,接收请求并委托给特定策略类处理。

策略模式重构示例

定义规则(策略),封装表单校验逻辑:

const strategies = {
  isNonEmpty: function (value, errMsg) {
    if (value === '') {
      return errMsg;
    }
  },
  minLenth: function (value, length, errMsg) {
    if (value.length < length) {
      return errMsg;
    }
  },
  isMobile: function (value, errMsg) {
    if (!/^1[3|5|8][0-9]{9}$/.test(value)) {
      return errMsg;
    }
  }
}

定义环境类 Context,执行表单校验并调用策略:

form.onsubmit = function () {
	const validator = new Validator();
	validator.add(form.userName, 'isNonEmpty', '用户名不能为空');
	validator.add(form.password, 'minLength:6', '密码长度不能少于6位');
	validator.add(form.phoneNumber, 'isMobile', '手机号码格式不正确');
	const errMsg = validator.start();
	if (errMsg) {
		alert(errMsg);
		return false;
	}
}

Validator 类源码如下:

class Validator {
	constructor() {
		this.cache = [];
	}
	add(dom, rule, errMsg) {
		const arr = rule.split(':');
		this.cache.push(() => {
			const strategy = arr.shift();
			arr.unshift(dom.value);
			arr.push(errMsg);
			return strategies[strategy].apply(dom, arr);
		})
	}
	start() {
		for (let i = 0; i < this.cache.length; i++) {
			const msg = this.cache[i]();
			if (msg) return msg;
		}
	}
}

重构后消除了原程序大量条件分支。通过“配置”方式完成表单校验,规则可在程序任意处复用,并可作为插件移植至其他项目。

策略模式优劣分析

优势:

  • 有效规避多重条件选择语句。
  • 完美支持开放-封闭原则,将算法封装于独立 strategy 中,便于切换、理解与扩展。
  • 支持算法在系统其他部分复用,避免大量复制粘贴工作。

劣势:

  • 引入策略模式会增加程序中策略类或策略对象的数量。
  • 使用策略模式需知晓所有 strategy 及其差异,以便选择合适的 strategy,这违背最少知识原则。

策略模式适用场景

💡 若对象内含多种算法变体且需运行时切换,可使用策略模式。

策略模式允许将对象关联至不同子对象,以间接方式在运行时变更对象行为,这些子对象以不同方式执行特定子任务。

💡 若存在多个仅在执行某些行为时略有差异的相似类,可使用策略模式。

策略模式允许将不同行为抽取至独立类层次结构,并将原始类组合为同一类,从而减少重复代码。

💡 若算法在上下文逻辑中非核心,使用该模式可将类业务逻辑与算法实现细节隔离。

策略模式允许将各种算法的代码、内部数据及依赖关系与其他代码隔离。不同客户端可通过简单接口执行算法,并支持运行时切换。

💡 若类中使用复杂条件运算符在同一算法的不同变体间切换,可使用该模式。

策略模式将所有继承自同一接口的算法抽取至独立类,从而消除条件语句。原始对象不实现所有算法变体,而是将执行工作委派给其中一个独立算法对象。

总结

前述示例中,使用策略模式虽增加策略对象及执行代码,但这些代码可在应用任意位置的表单复用,大幅减少总代码量且易于维护。下次面对多表单校验需求,勿再编写冗余 if-else 逻辑,建议尝试策略模式!

参考

深入设计模式——策略模式

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

更多关于js前端设计模式优化表单校验的资料请关注本站其它相关文章!

作者最新文章