设计模式之------策略模式

一、什么是策略模式?

‌策略模式(Strategy Pattern) ‌ 是一种通过定义一系列可互换的算法,并将其封装成独立对象的设计模式。在前端开发中,它允许我们‌动态切换业务逻辑 ‌,避免复杂的条件判断(如 if-else 或 switch-case),提升代码的可维护性和扩展性。

核心特征:

  • ‌算法独立‌:每个策略封装一个独立算法
  • ‌动态切换‌:运行时自由替换策略
  • ‌去条件化‌:消除多层嵌套的条件分支

二、前端使用场景及实现示例

场景1:表单验证策略(基础场景)

‌需求‌:对不同输入类型(邮箱、手机号、密码)使用不同的校验规则

typescript 复制代码
// 策略对象定义
const validationStrategies = {
  email: (value) => /^[^\s@]+@[^\s@]+.[^\s@]+$/.test(value),
  phone: (value) => /^1[3-9]\d{9}$/.test(value),
  password: (value) => value.length >= 6 && /\d/.test(value) && /[a-zA-Z]/.test(value)
};

// 验证上下文
function validateInput(type, value) {
  const strategy = validationStrategies[type];
  if (!strategy) throw new Error('未知验证类型');
  return strategy(value);
}

// 使用示例
console.log(validateInput('email', 'test@example.com')); // true
console.log(validateInput('password', 'weak')); // false

‌优化点 ‌:新增校验规则只需扩展 validationStrategies 对象,无需修改 validateInput 函数。


场景2:订单折扣策略(中等复杂度)

‌需求‌:根据不同的促销类型(满减、折扣、无优惠)计算订单价格

javascript 复制代码
// 策略类定义
class DiscountStrategy {
  static FULL_REDUCTION(total) {
    return total >= 200 ? total - 50 : total;
  }

  static PERCENTAGE(total) {
    return total * 0.8;
  }

  static NONE(total) {
    return total;
  }
}

// React组件实现
function OrderCalculator({ promotionType }) {
  const [total, setTotal] = useState(0);

  const calculateFinal = () => {
    return DiscountStrategy[promotionType]?.(total) ?? total;
  };

  return (
    <div>
      <input type="number" onChange={e => setTotal(parseFloat(e.target.value))} />
      <p>最终价格: {calculateFinal()}</p>
    </div>
  );
}

// 使用示例
<OrderCalculator promotionType="PERCENTAGE" />

‌优化点‌:策略与UI组件解耦,促销策略变化不影响组件逻辑。


场景3:数据可视化渲染(复杂场景)

‌需求‌:根据数据类型动态选择图表渲染引擎(ECharts、D3.js、Canvas)

typescript 复制代码
// 策略接口定义
interface ChartStrategy {
  render(data: DataSet): void;
  destroy(): void;
}

// 具体策略实现
const EChartsStrategy: ChartStrategy = {
  render(data) {
    const chart = echarts.init(document.getElementById('chart'));
    chart.setOption({/* ... */});
  },
  destroy() {
    echarts.dispose(document.getElementById('chart'));
  }
};

const D3Strategy: ChartStrategy = {
  render(data) {
    d3.select('#chart')
      .selectAll('rect')
      .data(data)
      .join('rect') 
      .attr('width', d => d.value);
  },
  destroy() {
    d3.select('#chart').selectAll('*').remove();
  }
};

// 策略上下文(Vue3实现)
const useChartRenderer = (strategy: ChartStrategy) => {
  onMounted(() => strategy.render(props.data));
  onBeforeUnmount(() => strategy.destroy());
};

// 组件调用
<template>
  <div id="chart" />
</template>

<script setup>
import { useChartRenderer } from './chartHooks';

// 根据用户配置选择引擎
const strategy = computed(() => 
  userConfig.renderEngine === 'd3' ? D3Strategy : EChartsStrategy
);

useChartRenderer(strategy.value);
</script>

‌优化点‌:渲染引擎实现细节被完全封装,切换策略不影响业务逻辑。


三、策略模式在前端的优势

场景类型 传统实现问题 策略模式优势
表单验证 需要多层if-else判断校验类型 通过策略对象属性直接索引
价格计算 促销逻辑与组件深度耦合 策略独立维护,支持动态热更新
数据可视化 切换渲染引擎需要重写大量代码 策略接口统一,实现即插即用

四、何时使用策略模式?

  1. ‌存在同类算法的多种实现‌(如不同的验证规则、计算方式)
  2. ‌需要动态切换算法‌(如用户选择不同的展示方式)
  3. ‌需要隔离复杂算法逻辑‌(如图表渲染引擎封装)

经典应用案例:

  • 国际化(根据语言选择翻译策略)
  • 权限校验(不同用户角色对应不同校验规则)
  • 文件上传(阿里云OSS、腾讯云COS等不同云存储切换)

五、实现要点

  1. ‌定义清晰的策略接口‌(TypeScript接口最佳)
  2. ‌使用对象字面量或类统一管理策略‌
  3. ‌通过工厂模式动态创建策略‌(可选)
  4. ‌结合依赖注入控制策略生命周期‌(推荐在框架中使用)
ini 复制代码
// 策略工厂示例
const strategyFactory = (type) => {
  const strategies = {
    A: StrategyA,
    B: StrategyB
  };
  return strategies[type] || DefaultStrategy;
};

六、与相似模式对比

模式 区别
‌工厂模式‌ 关注对象创建,策略模式关注行为选择
‌状态模式‌ 状态变化驱动行为,策略主动选择
‌装饰器模式‌ 动态添加功能,策略模式替换整体算法

通过策略模式,前端开发者可以构建更灵活、更易维护的应用程序。特别是在现代前端框架(React/Vue)的组件化开发中,合理使用策略模式能显著提升复杂业务场景下的代码质量。

相关推荐
怕浪猫6 小时前
RAG 面试 6 连问,从原理到优化全部覆盖
python·算法·面试
To_OC8 小时前
从一头雾水到跑通全流程:我用一个周末啃透了JWT登录鉴权
前端·后端·http
excel9 小时前
研究 Vue 3 源码的收获
前端·vue.js
可乐鸡翅yeah_11 小时前
业务中 M3U8 水印相关坑,硬水印和动态水印区别
前端·网络·数据库·ffmpeg·m3u8在线
lerhxx11 小时前
AI 应用如何高效优雅地恢复中断?—— "连接解耦 + 状态持久化"
前端·javascript
计算机魔术师11 小时前
METR 演示 AI 智能体如何篡改 Inspect 评估记录以掩盖不当行为
前端
前端snow12 小时前
ai agent --- 异步处理之 Rabbit MQ
前端
念何架构之路12 小时前
zap扩展生态与总结
java·前端·数据库
独孤九剑打醒他12 小时前
【原创开源】【概念设计】源 - 栅 - 漏 - 栅 - 源 横向双栅 MOS,低压交流多值逻辑芯片探索
前端·其他·架构·开源·硬件工程
mantou13213 小时前
我给 AI Agent 做了个「油猴」:让 Claude Code / Codex 直接用你已登录的浏览器
前端·javascript·后端