策略模式
用 JavaScript 实现策略模式,消除条件分支
问题
什么是策略模式?如何用 JavaScript 实现?
解答
策略模式将一系列算法封装成独立的策略对象,使它们可以相互替换,避免大量的 if-else 或 switch-case。
场景:表单验证
不使用策略模式的写法:
function validate(value, type) {
if (type === 'required') {
return value !== '';
} else if (type === 'email') {
return /^[\w-]+@[\w-]+\.\w+$/.test(value);
} else if (type === 'phone') {
return /^1[3-9]\d{9}$/.test(value);
}
// 每增加一种验证,就要改这个函数
}
使用策略模式:
// 策略对象:每种验证规则是一个策略
const strategies = {
required(value) {
return value !== '' || '不能为空';
},
email(value) {
return /^[\w-]+@[\w-]+\.\w+$/.test(value) || '邮箱格式错误';
},
phone(value) {
return /^1[3-9]\d{9}$/.test(value) || '手机号格式错误';
},
minLength(value, length) {
return value.length >= length || `最少 ${length} 个字符`;
}
};
// 验证器:使用策略
class Validator {
constructor() {
this.rules = [];
}
// 添加验证规则
add(value, rule) {
const [strategyName, ...params] = rule.split(':');
this.rules.push(() => strategies[strategyName](value, ...params));
}
// 执行验证
validate() {
for (const rule of this.rules) {
const result = rule();
if (result !== true) {
return result; // 返回错误信息
}
}
return true;
}
}
// 使用
const validator = new Validator();
validator.add('', 'required');
validator.add('test@example.com', 'email');
validator.add('abc', 'minLength:6');
const result = validator.validate();
console.log(result); // "不能为空"
场景:价格计算
// 策略对象:不同会员等级的折扣策略
const priceStrategies = {
normal: (price) => price,
vip: (price) => price * 0.9,
svip: (price) => price * 0.8,
blackCard: (price) => price * 0.7
};
// 计算价格
function calculatePrice(price, level) {
return priceStrategies[level](price);
}
console.log(calculatePrice(100, 'vip')); // 90
console.log(calculatePrice(100, 'svip')); // 80
场景:动画缓动函数
// 缓动策略
const easingStrategies = {
linear: (t) => t,
easeIn: (t) => t * t,
easeOut: (t) => t * (2 - t),
easeInOut: (t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t)
};
function animate(duration, easing, callback) {
const start = performance.now();
const easingFn = easingStrategies[easing];
function tick(now) {
const progress = Math.min((now - start) / duration, 1);
callback(easingFn(progress));
if (progress < 1) {
requestAnimationFrame(tick);
}
}
requestAnimationFrame(tick);
}
// 使用
animate(1000, 'easeOut', (value) => {
element.style.opacity = value;
});
关键点
- 策略模式把算法封装成对象,通过组合替代继承
- 消除 if-else/switch-case,新增策略无需修改原有代码
- JavaScript 中函数是一等公民,策略可以直接用函数表示
- 适用场景:表单验证、价格计算、动画缓动、权限判断等
- 符合开闭原则:对扩展开放,对修改关闭
目录