本文通过注册页面表单校验案例,分析传统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前端设计模式优化表单校验的资料请关注本站其它相关文章!