【设计模式】【前端】 JavaScript 如何实现策略模式

前端 JavaScript 如何实现策略模式?

在前端开发中,策略模式常用于:

  • 表单验证(不同输入字段不同校验规则)
  • 排序算法(支持多种排序方式)
  • 支付方式切换(微信支付、支付宝、银行卡)
  • 动画策略(不同的动画效果)

一、策略模式的 JavaScript 实现

1. 传统写法(多方法模式,不符合策略模式)

如果不使用策略模式,可能会像这样写:

javascript 复制代码
class Calculator {
    add(a, b) {
        return a + b;
    }

    subtract(a, b) {
        return a - b;
    }

    multiply(a, b) {
        return a * b;
    }
}

const calc = new Calculator();
console.log(calc.add(10, 5));       // 15
console.log(calc.subtract(10, 5));  // 5
console.log(calc.multiply(10, 5));  // 50

问题:

  • 不符合"开闭原则" :如果要新增除法方法,需要修改 Calculator 类。
  • 难以动态切换策略:必须手动调用不同的方法,而不是动态选择。

2. 使用策略模式(符合 OCP 原则)

我们用对象字面量 + 高阶函数来实现策略模式:

(1) 定义策略对象

javascript 复制代码
const strategies = {
    add: (a, b) => a + b,
    subtract: (a, b) => a - b,
    multiply: (a, b) => a * b
};

(2) 定义 Context 上下文

javascript 复制代码
class Context {
    constructor(strategy) {
        this.strategy = strategy;
    }

    setStrategy(strategy) {
        this.strategy = strategy;  // 允许动态更换策略
    }

    executeStrategy(a, b) {
        return this.strategy(a, b);
    }
}

(3) 运行时动态切换策略

javascript 复制代码
const context = new Context(strategies.add);  // 设定初始策略为加法
console.log("10 + 5 =", context.executeStrategy(10, 5));  // 15

context.setStrategy(strategies.subtract);  // 切换为减法
console.log("10 - 5 =", context.executeStrategy(10, 5));  // 5

context.setStrategy(strategies.multiply);  // 切换为乘法
console.log("10 * 5 =", context.executeStrategy(10, 5));  // 50

二、前端实际应用案例

1. 表单验证策略

在前端开发中,我们常需要对不同的输入字段执行不同的验证规则,例如:

  • 邮箱格式 :必须包含 @
  • 手机号格式:必须是 11 位数字
  • 密码长度:至少 6 位

(1) 定义验证策略

javascript 复制代码
const validationStrategies = {
    isNonEmpty: (value) => value.trim() !== "" || "不能为空",
    isEmail: (value) => /\S+@\S+\.\S+/.test(value) || "邮箱格式不正确",
    isPhone: (value) => /^\d{11}$/.test(value) || "手机号格式不正确",
    minLength: (min) => (value) => value.length >= min || `长度不能少于 ${min} 位`
};

(2) 验证函数

javascript 复制代码
function validate(value, rules) {
    for (const rule of rules) {
        const result = rule(value);
        if (result !== true) {
            return result; // 返回第一个错误信息
        }
    }
    return true;
}

(3) 使用策略进行表单验证

javascript 复制代码
const emailInput = "[email protected]";
const phoneInput = "13800138000";
const passwordInput = "12345";

console.log(validate(emailInput, [validationStrategies.isNonEmpty, validationStrategies.isEmail]));
// 输出: true

console.log(validate(phoneInput, [validationStrategies.isNonEmpty, validationStrategies.isPhone]));
// 输出: true

console.log(validate(passwordInput, [validationStrategies.isNonEmpty, validationStrategies.minLength(6)]));
// 输出: "长度不能少于 6 位"

好处:

  • 新增校验规则时,不需要修改 validate 函数,只需扩展 validationStrategies

2. 购物车优惠策略

电商系统通常会有不同的折扣策略:

  • 满 100 减 10
  • VIP 会员打 9 折
  • 满 200 送 20 元代金券

(1) 定义折扣策略

javascript 复制代码
const discountStrategies = {
    noDiscount: (price) => price,
    tenOffIfOver100: (price) => price >= 100 ? price - 10 : price,
    vipDiscount: (price) => price * 0.9,
    couponFor200: (price) => price >= 200 ? price - 20 : price
};

(2) 定义上下文

javascript 复制代码
class Cart {
    constructor(strategy) {
        this.strategy = strategy;
    }

    setStrategy(strategy) {
        this.strategy = strategy;
    }

    calculateTotal(price) {
        return this.strategy(price);
    }
}

(3) 使用折扣策略

javascript 复制代码
const cart = new Cart(discountStrategies.noDiscount);
console.log("原价 150,折扣后 =", cart.calculateTotal(150));  // 150

cart.setStrategy(discountStrategies.tenOffIfOver100);
console.log("原价 150,折扣后 =", cart.calculateTotal(150));  // 140

cart.setStrategy(discountStrategies.vipDiscount);
console.log("原价 150,VIP 价格 =", cart.calculateTotal(150));  // 135

好处:

  • 支持多种折扣策略,动态切换
  • 符合开闭原则,扩展新策略时无需修改 Cart 代码

三、策略模式在前端的适用场景

场景 示例
表单验证 根据输入类型选择不同的验证规则
支付方式 切换支付宝、微信、银行卡支付
动画策略 切换淡入淡出、滑动动画等不同的实现
排序方法 提供不同的排序策略(冒泡、快速、插入排序)
数据格式化 不同地区的时间、货币格式化

四、总结

策略模式适用于多个可替换算法的场景,并且能在运行时动态切换策略。

在前端,常用于表单验证、支付方式、购物车折扣等场景。

用对象字面量 + 高阶函数可以更简洁地实现策略模式。

符合 SOLID 原则,尤其是"开闭原则(OCP)",让代码更易扩展。

🚀 在前端开发中,如果你发现 if-else 语句过多,并且算法可能会变化,就可以考虑策略模式!

策略模式 vs. switch 语句

在前端开发中,很多人会用 switch 语句来处理不同的逻辑,比如:

  • 处理不同的 支付方式 (switch(paymentType))
  • 处理不同的 用户角色 (switch(userRole))
  • 处理不同的 排序方式 (switch(sortType))

switch 有一些 缺点 ,而 策略模式(Strategy Pattern) 可以优化代码,让代码更清晰、更易扩展。


一、使用 switch 的实现

示例:计算器

我们先用 switch 语句来实现一个简单的计算器:

javascript 复制代码
function calculate(operation, a, b) {
    switch (operation) {
        case "add":
            return a + b;
        case "subtract":
            return a - b;
        case "multiply":
            return a * b;
        case "divide":
            return b !== 0 ? a / b : "Cannot divide by zero";
        default:
            return "Invalid operation";
    }
}

console.log(calculate("add", 10, 5));       // 15
console.log(calculate("subtract", 10, 5));  // 5
console.log(calculate("multiply", 10, 5));  // 50
console.log(calculate("divide", 10, 5));    // 2

switch 的缺点

违背开闭原则(OCP)

  • 每次新增运算方式(如 modulus 取余),必须修改 calculate 函数
  • 高耦合度 :所有逻辑都写在 calculate 里,代码难以维护。

难以动态扩展

  • 不能在运行时轻松切换策略。
  • 代码可读性变差,switch 语句可能变得很长。

二、使用策略模式优化

策略对象

javascript 复制代码
const strategies = {
    add: (a, b) => a + b,
    subtract: (a, b) => a - b,
    multiply: (a, b) => a * b,
    divide: (a, b) => (b !== 0 ? a / b : "Cannot divide by zero"),
};

策略上下文

javascript 复制代码
class Context {
    constructor(strategy) {
        this.strategy = strategy;
    }

    setStrategy(strategy) {
        this.strategy = strategy; // 允许动态切换策略
    }

    execute(a, b) {
        return this.strategy(a, b);
    }
}

运行时动态切换

javascript 复制代码
const context = new Context(strategies.add);
console.log(context.execute(10, 5));  // 15

context.setStrategy(strategies.subtract);
console.log(context.execute(10, 5));  // 5

context.setStrategy(strategies.multiply);
console.log(context.execute(10, 5));  // 50

三、switch vs. 策略模式对比

对比项 switch 语句 策略模式
开闭原则(OCP) 需要修改原代码,违背 OCP 新增策略时不改动原代码,符合 OCP
代码结构 逻辑集中在一个函数,耦合度高 策略独立,结构清晰
可扩展性 难以扩展,每新增一个策略,都要改 switch 代码 只需新增一个策略对象,完全不影响现有代码
可读性 switch 可能变得很长,可读性下降 策略模式让代码更清晰,避免 if-elseswitch
动态切换策略 不能在运行时更改,只能靠 if-elseswitch 可以在运行时灵活切换策略

四、策略模式的适用场景

适合的场景

  • 代码中包含多个可替换的算法(如支付方式、验证规则)。
  • 需要动态切换不同的策略,而不是用 if-elseswitch 硬编码。
  • 代码需要符合 开闭原则(OCP),避免频繁修改核心逻辑。

不适合的场景

  • 如果策略数量很少(只有 2-3 个),使用 switchif-else 更简单。
  • 如果策略不会发生变化,不需要动态扩展。

五、总结

🚀 什么时候用 switch

  • 逻辑简单,策略固定,策略数量少时(如 2-3 个)。

🚀 什么时候用策略模式?

  • 策略数量多 ,可能动态扩展(如表单校验、支付方式、动画效果)。
  • 希望代码清晰、可读性高 ,避免 switch 语句过长。
  • 希望符合 SOLID 原则 ,特别是开闭原则(OCP)

一句话总结
如果 switch 代码很长,或者需要在运行时动态切换策略,就应该用策略模式! 🎯

相关推荐
小满zs13 分钟前
React-router v7 第一章(安装)
前端·react.js
程序员小续19 分钟前
前端低代码架构解析:拖拽 UI + 代码扩展是怎么实现的?
前端·javascript·面试
wangpq27 分钟前
微信小程序地图callout气泡图标在ios显示,在安卓机不显示
前端·vue.js
curdcv_po30 分钟前
Vue3 组件通信方式全解析
前端
Auroral15635 分钟前
基于RabbitMQ的异步通知系统设计与实现
前端·后端
栗筝i35 分钟前
Spring 核心技术解析【纯干货版】- XV:Spring 网络模块 Spring-Web 模块精讲
前端·网络·spring
打野赵怀真38 分钟前
H5如何禁止动画闪屏?
前端·javascript
zhangxingchao38 分钟前
关于浮点数的思考
前端
Riesenzahn38 分钟前
你喜欢Sass还是Less?为什么?
前端·javascript