如何用JavaScript实现策略模式
策略模式是一种常用的设计模式,它的核心思想是定义一系列算法,把它们封装起来,并且使它们可以相互替换。使用策略模式可以避免大量的条件判断语句,让代码更易于维护和扩展。在JavaScript中,由于其函数是一等公民的特性,实现策略模式会非常简洁直观。
策略模式的核心结构
策略模式通常包含两个部分:
- 策略类(或策略对象):封装了具体的算法实现,每个策略对应一种具体的操作逻辑。
- 环境类(或上下文):持有一个策略对象的引用,负责根据需求调用对应的策略执行逻辑。
基础实现示例:计算不同会员等级的折扣
我们以电商场景中不同会员等级享受不同折扣为例,演示策略模式的实现。假设平台有普通会员(无折扣)、银卡会员(9折)、金卡会员(8折)三种等级,传统写法可能会用if-else或者switch判断会员等级再计算价格,而用策略模式可以把折扣逻辑拆分到不同的策略中。
// 定义折扣策略对象,每个属性对应一种会员等级的折扣计算逻辑
const discountStrategies = {
// 普通会员:无折扣,返回原价
normal: function(price) {
return price;
},
// 银卡会员:9折
silver: function(price) {
return price * 0.9;
},
// 金卡会员:8折
gold: function(price) {
return price * 0.8;
}
};
// 定义价格计算上下文函数,接收原价和会员等级,调用对应策略计算最终价格
function calculatePrice(price, memberLevel) {
// 如果传入的会员等级没有对应的策略,默认使用普通会员策略
const strategy = discountStrategies[memberLevel] || discountStrategies.normal;
return strategy(price);
}
// 测试示例
console.log(calculatePrice(100, 'normal')); // 输出:100
console.log(calculatePrice(100, 'silver')); // 输出:90
console.log(calculatePrice(100, 'gold')); // 输出:80
console.log(calculatePrice(100, 'platinum')); // 未定义的等级,输出:100上面的代码中,discountStrategies就是策略对象,每个属性对应一种折扣策略的具体实现。calculatePrice是上下文函数,它不需要关心具体的折扣计算逻辑,只需要根据传入的会员等级找到对应的策略执行即可。如果后续要新增铂金会员7折的规则,只需要在discountStrategies中新增一个platinum属性即可,不需要修改上下文函数的逻辑,符合开闭原则。
进阶实现:支持动态切换策略的上下文类
如果场景需要更灵活的策略管理,比如可以在运行时动态切换策略,我们可以把上下文封装成一个类,在类中维护当前使用的策略,提供更清晰的接口。
// 定义策略对象,和上面的示例类似,也可以拆分成多个独立的策略类
const paymentStrategies = {
// 微信支付策略
wechat: function(amount) {
console.log(`使用微信支付,支付金额:${amount}元`);
// 这里可以写实际的微信支付调用逻辑
return true;
},
// 支付宝支付策略
alipay: function(amount) {
console.log(`使用支付宝支付,支付金额:${amount}元`);
// 这里可以写实际的支付宝支付调用逻辑
return true;
},
// 银行卡支付策略
bankCard: function(amount) {
console.log(`使用银行卡支付,支付金额:${amount}元`);
// 这里可以写实际的银行卡支付调用逻辑
return true;
}
};
// 支付上下文类
class PaymentContext {
constructor(initialStrategy) {
// 初始化默认支付策略
this.strategy = initialStrategy;
}
// 设置新的支付策略
setStrategy(strategyName) {
if (paymentStrategies[strategyName]) {
this.strategy = strategyName;
} else {
throw new Error(`不支持的支付策略:${strategyName}`);
}
}
// 执行支付操作
pay(amount) {
const strategyFunc = paymentStrategies[this.strategy];
if (!strategyFunc) {
throw new Error('未设置有效的支付策略');
}
return strategyFunc(amount);
}
}
// 测试示例
const payment = new PaymentContext('wechat');
payment.pay(50); // 输出:使用微信支付,支付金额:50元
payment.setStrategy('alipay');
payment.pay(100); // 输出:使用支付宝支付,支付金额:100元
payment.setStrategy('bankCard');
payment.pay(200); // 输出:使用银行卡支付,支付金额:200元这个实现中,PaymentContext类封装了策略的管理和调用逻辑,用户不需要直接接触具体的支付策略,只需要通过上下文提供的setStrategy和pay方法操作即可。如果后续要新增云闪付的支付方式,只需要在paymentStrategies中新增对应的策略函数,再在上下文中调用setStrategy('unionpay')就可以使用,扩展性非常好。
策略模式的适用场景
在JavaScript开发中,以下场景可以考虑使用策略模式:
- 代码中出现了大量的条件判断语句,比如根据不同类型的状态执行不同的逻辑,且这些条件判断可能会频繁新增或修改。
- 需要把算法封装起来,让它们可以被替换、复用,避免算法逻辑和调用逻辑耦合在一起。
- 有多个类似的业务逻辑,只是具体的实现细节不同,比如不同的表单校验规则、不同的动画效果实现等。
注意事项
虽然策略模式有很多优点,但也不是所有场景都适合使用。如果只有很少的几种算法,而且后续不会扩展,使用策略模式反而会增加代码的复杂度,这时候直接用条件判断反而更简洁。另外,策略模式中的策略对象如果没有做好管理,可能会出现策略过多难以维护的问题,这时候可以考虑把相关的策略按模块拆分,或者给策略增加描述信息方便管理。
JavaScript策略模式设计模式算法封装代码重构前端开发 本作品最后修改时间:2026-05-22 14:04:40