策略模式(Strategy)
用一个需求引入:一堆 if/else 正在失控
假设你在做一个电商前端:运费计算规则经常变。
- 普通用户:运费 12
- 会员:运费 6
- 超级会员:免运费
- 新增:不同城市、不同重量、促销活动还要叠加……
很多人第一反应是写成:
if/else越堆越多- 一个规则改动,容易影响其他逻辑
- 测试难、复用难、扩展难
这类“同一个目标,根据不同条件选择不同算法/规则”的问题,就是策略模式很适合解决的场景。
策略模式是什么(关键点讲清楚)
策略模式(Strategy Pattern):把一组可互换的“策略/算法”封装起来,通过一个“上下文”在运行时选择其中一个执行。
把它拆成三个要点就很清晰:
- 策略(Strategy):每个策略是一套独立规则(一个函数/对象)。
- 上下文(Context):负责选择并调用策略(通常是一个统一入口)。
- 可替换性:新增/修改策略,不需要改动调用方的核心流程(减少
if/else扩散)。
一句话总结:把“选择哪种做法”和“具体怎么做”解耦。
一个简单代码例子:运费计算(从 if/else 到策略)
1)传统写法(问题明显)
function calcShipping(userType, amount) {
if (userType === 'normal') {
return 12;
} else if (userType === 'vip') {
return 6;
} else if (userType === 'svip') {
return 0;
} else {
throw new Error('未知用户类型');
}
}
当你加入“满 99 免运费”“北京特殊规则”时,这个函数会迅速膨胀。
2)策略模式写法(规则可插拔)
// 1) 策略集合:每个策略只关心自己的规则
const shippingStrategies = {
normal({ amount }) {
return amount >= 99 ? 0 : 12;
},
vip({ amount }) {
return amount >= 99 ? 0 : 6;
},
svip() {
return 0;
}
};
// 2) 上下文:统一入口,负责选择策略并执行
function calcShipping(userType, payload) {
const strategy = shippingStrategies[userType];
if (!strategy) throw new Error(`未知用户类型: ${userType}`);
return strategy(payload);
}
// 3) 使用
calcShipping('normal', { amount: 88 }); // 12
calcShipping('vip', { amount: 120 }); // 0
calcShipping('svip', { amount: 1 }); // 0
扩展时怎么做?
新增一个类型(比如 student),只要加一个策略函数即可,不必去“改动旧逻辑”:
shippingStrategies.student = ({ amount }) => (amount >= 50 ? 0 : 8);
前端常见应用场景(非常实用)
-
表单校验策略
- 不同字段、不同规则(必填、邮箱、手机号、密码强度…)
- 通过策略组合实现“可配置校验器”
-
权限与路由控制
- 不同角色对应不同的可访问规则
- 把“能不能进”的规则策略化,避免路由守卫里塞满判断
-
UI 行为差异(多端/多渠道)
- 同一个按钮点击:在 App 内打开 WebView、在 H5 跳转、在小程序走另一套 API
- 用策略封装差异逻辑
-
数据展示/格式化
- 不同币种、不同语言、不同日期格式
formatterStrategies[type](value)替代大量分支
-
业务规则频繁变化的计算
- 优惠券叠加规则、价格计算、积分计算等
- 把规则封装成策略,配合配置驱动更稳
注意事项(避免“用了模式反而更乱”)
-
别为了模式而模式
- 如果只有 2 个分支、且长期不会变,简单
if可能更清晰 - 策略模式适合“分支多、变化频繁、可扩展需求明显”的场景
- 如果只有 2 个分支、且长期不会变,简单
-
策略命名要清晰、输入输出要统一
- 最好让所有策略签名一致:
(payload) => result - 否则上下文会被迫做兼容,复杂度回流
- 最好让所有策略签名一致:
-
要处理“找不到策略”的兜底
- 抛错、默认策略、日志告警要明确
- 否则静默失败会很难排查
-
策略不要偷偷依赖外部可变状态
- 例如直接读全局变量、随意改共享对象
- 建议把依赖显式放到
payload或通过参数注入
-
策略过多时要分层/分目录管理
- 规则几十个以后,建议按业务域拆文件、做注册表
- 避免一个巨大
strategies对象难以维护
小结
策略模式在前端最常见的价值是:把不断增长的条件分支,变成可维护、可扩展的“规则集合”。当需求不断变化、规则不断新增时,它能显著降低修改风险,提升复用与测试效率。