一、什么是策略模式?
策略模式(Strategy Pattern)属于行为型设计模式。核心思路是将一组可替换的算法封装在独立的类中,使它们可以在运行时动态切换,同时使客户端代码与具体算法解耦。它包含三个核心角色:
- 策略接口(Strategy Interface):定义算法的方法签名
- 具体策略(Concrete Strategies):实现具体算法逻辑
- 上下文(Context):持有一个策略对象,并调用其方法
通俗比喻:把算法当作「插件」,客户端只需要选择对应插件插入到主流程中,不需要关注插件内部实现。
二、适用场景
_以下场景常见于前端开发:_
- 同类功能的多算法切换
👉 表单验证(邮箱、手机号、身份证等校验规则)、数据导出(CSV、Excel、PDF格式)、图表渲染(折线图、柱状图) - 需要动态选择行为的场景
👉 动态折扣计算(满减、折扣券、积分抵扣)、权限校验(不同角色对应不同校验规则) - 消除臃肿的条件分支
👉 存在大量if-else
或switch-case
的场景(如老代码中的支付方式处理) - 需要隐藏复杂算法的实现
👉 地图路径规划(步行、驾车、公交策略)、动画缓动函数(linear、ease-in)
三、实战代码示例
案例1:表单验证策略
// 策略接口:定义 validate 方法
class ValidationStrategy {
validate(value) {
throw new Error("必须实现 validate 方法!");
}
}
// 具体策略:非空校验
class RequiredValidation extends ValidationStrategy {
validate(value) {
return value.trim() !== "";
}
}
// 具体策略:手机号校验
class MobileValidation extends ValidationStrategy {
validate(value) {
return /^1[3-9]\d{9}$/.test(value);
}
}
// 上下文类:管理当前策略
class ValidatorContext {
constructor(strategy) {
this.strategy = strategy;
}
setStrategy(strategy) {
this.strategy = strategy;
}
execute(value) {
return this.strategy.validate(value);
}
}
// 使用示例
const validator = new ValidatorContext(new RequiredValidation());
console.log(validator.execute("")); // 输出 false
validator.setStrategy(new MobileValidation());
console.log(validator.execute("13800138000")); // 输出 true
代码亮点:
- 添加新校验规则只需新增策略类,无须修改
ValidatorContext
- 客户端通过
.setStrategy()
动态切换算法
案例2:动态数据导出(常用功能增强)
// 策略接口:导出方法
class ExportStrategy {
export(data) {
throw new Error("必须实现 export 方法");
}
}
// 具体策略-导出为 CSV
class CsvExport extends ExportStrategy {
export(data) {
const csvContent = data.map(row => row.join(",")).join("\n");
console.log(`导出 CSV 成功,内容:${csvContent}`);
}
}
// 具体策略-导出为 Excel(伪代码)
class ExcelExport extends ExportStrategy {
export(data) {
// 假装调用了 Excel 库
console.log("生成 Excel 文件并下载");
}
}
// 上下文(可与 UI 结合)
class Exporter {
constructor() {
this.strategy = new CsvExport(); // 默认策略
}
setFormat(format) {
if (format === 'csv') {
this.strategy = new CsvExport();
} else if (format === 'excel') {
this.strategy = new ExcelExport();
}
}
executeExport(data) {
this.strategy.export(data);
}
}
// 使用示例
const exporter = new Exporter();
exporter.setFormat('excel');
exporter.executeExport([['Name', 'Age'], ['John', 30]]);
应用场景:
不同导出格式的代码集中到策略类中,避免主模块代码混乱。
四、开发建议与避坑指南
推荐做法:
- 组合优于继承:
用策略对象组合到上下文类,而非通过继承实现多态 - 接口约束:TypeScript 更优
interface Strategy { execute(data: any): void; }
- 策略命名清晰:
用MobileValidationStrategy
而非Strategy1
,便于维护 - 无状态策略:
尽量将策略设计为无状态(纯函数),可通过单例复用
常见陷阱:
- 过度设计:
👉 若只有1~2种固定算法,直接if-else
更简单 - 客户端感知策略细节:
👉 违反迪米特法则,应当由上下文类处理策略选择 - 策略间参数不一致:
👉 校验策略统一接收字符串,而非有的需要value
,有的需要formData
- 性能损耗:
👉 频繁创建策略对象时,可考虑对象池缓存
策略模式是应对算法多样化和动态切换需求的强大工具,前端开发中使用频率较高。
正确使用可显著提升代码可维护性,但在简单场景下需权衡是否引入复杂度。关键在于识别行为的变化点,将其独立出来。