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

一、什么是策略模式?

策略模式(Strategy Pattern) ‌ 是一种通过定义一系列可互换的算法,并将其封装成独立对象的设计模式。在前端开发中,它允许我们‌动态切换业务逻辑 ‌,避免复杂的条件判断(如 if-elseswitch-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', '[email protected]')); // 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)的组件化开发中,合理使用策略模式能显著提升复杂业务场景下的代码质量

相关推荐
—Qeyser5 小时前
用 Deepseek 写的uniapp血型遗传查询工具
前端·javascript·ai·chatgpt·uni-app·deepseek
codingandsleeping5 小时前
HTTP1.0、1.1、2.0 的区别
前端·网络协议·http
小满blue5 小时前
uniapp实现目录树效果,异步加载数据
前端·uni-app
喜樂的CC7 小时前
[react]Next.js之自适应布局和高清屏幕适配解决方案
javascript·react.js·postcss
天天扭码7 小时前
零基础 | 入门前端必备技巧——使用 DOM 操作插入 HTML 元素
前端·javascript·dom
软件测试曦曦7 小时前
16:00开始面试,16:08就出来了,问的问题有点变态。。。
自动化测试·软件测试·功能测试·程序人生·面试·职场和发展
咖啡虫7 小时前
css中的3d使用:深入理解 CSS Perspective 与 Transform-Style
前端·css·3d
烛阴8 小时前
手把手教你搭建 Express 日志系统,告别线上事故!
javascript·后端·express
旭久8 小时前
react+Tesseract.js实现前端拍照获取/选择文件等文字识别OCR
前端·javascript·react.js