JavaScript - 策略模式在开发中的应用

1. 什么是策略模式

策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。

它最主要的目的是将算法与环境区分开,让算法与环境之间解耦。

策略模式由两部分组成:

  1. 第一部分是策略类strategy,策略类负责封装多个算法
  2. 第二部分是环境类context,环境类负责调用策略类当中的某个算法

2. 策略模式示例

在使用策略模式时,需要将算法从环境中提取出来,封装到策略中,例如在未使用策略模式之前,你判断渲染组件的代码有可能是这样:

xml 复制代码
<template>
  <UserBoard v-if="userType === 'user'" />
  <StaffBoard v-else-if="userType === 'staff'" />
</template>

<script setup>
import { UserBoard } from '@/view/busi/user/userBoard.vue';
import { StaffBoard } from '@/view/busi/staff/staffBoard.vue';

const props = defineProps({
  userType: {
   type: String,
   required: true
  }
})
</script>

这种写法在组件较少的情况下是没有问题的,但需要判断渲染的组件一多,代码就很丑陋,可读性会变得很差,在这种情况下,我们就可以使用策略模式去定义一个映射。

使用了策略模式之后:

xml 复制代码
<template>
  <component :is="strategies[userType]"></component>
</template>

<script setup>
import { UserBoard } from '@/view/busi/user/userBoard.vue';
import { StaffBoard } from '@/view/busi/staff/staffBoard.vue';

const props = defineProps({
  userType: {
   type: String,
   required: true
  }
})

const strategies = {
  'user': UserBoard,
  'staff': StaffBoard
}
</script>

3. 策略模式在开发中的应用

在开发中很多时候会碰到Modal里只需要一两个输入框的场景,如果专门为了这个输入框去定义一整个表单的话,感觉是有点没必要的。常见的是使用if-else去判断输入框字段是否合法,那么可以使用策略模式,去定义一个useRules,在全局去进行使用。

typescript 复制代码
/**
 * ex:
 *  先添加需要验证的规则
 *  const ruleValidator = useRules();
 *  ruleValidator.addValidatorCache(phone,"isEmpty","请输入手机号");
 *  ruleValidator.addValidatorCache(phone,"isMobile",'请填写正确手机号格式');
 *  添加后验证: ruleValidator.check();
 * @returns {{addValidatorCache: addValidatorCache, check: (function(): null)}|{result: *, reason: *|string}}
 */
export function useRules() {
  const validatorCache = [];
  
  /**
   *
   * @param boolean {Boolean} - 验证结果
   * @param reason {String} - 报错原因
   * @returns {{result: {Boolean},reason?: {String}}}
   */
  const makeValidationResult = (boolean, reason) => {
   return {
    result: boolean,
    reason: boolean?reason:''
   }
  }
  
  const ruleStrategies = {
   /**
    *
    * @param refValue {Ref} - 验证值
    * @param reason {String} - 报错原因
    * @returns {{result: {Boolean},reason?: {String}}}
    */
   isEmpty(refValue, reason) {
    let value = refValue.value;
    return makeValidationResult(!value,reason);
   },
   
   /**
    *
    * @param refValue {Ref} - 验证值
    * @param maxLength {Number} - 最大长度
    * @param reason {String} - 报错原因
    * @returns {{result: {Boolean},reason?: {String}}}
    */
   isOverMaxLength(refValue, maxLength, reason) {
    let value = refValue.value;
    const boolean = value?.length > maxLength;
    return makeValidationResult(boolean,reason);
   },
   
   /**
    *
    * @param refValue {Ref} - 验证值
    * @param reason {String} - 报错原因
    * @returns {{result: {Boolean},reason?: {String}}}
    */
   isMobile(refValue, reason) {
    let value = refValue.value;
    const boolean = !/^1[34578]\d{9}$/.test(value);
    return makeValidationResult(boolean,reason);
   }
  }
  
  /**
   *
   * @param value {Ref} - 验证值
   * @param rule {String} - 形如 "isOverMaxLength:3"
   * @param errorMsg {String} - 报错消息
   */
  const addValidatorCache = (value, rule, errorMsg) => {
   const params = rule.split(':');
   let strategy = params.shift();
   params.unshift(value);
   params.push(errorMsg);
   validatorCache.push(() => {
    //传params到ruleStrategies[strategy]函数中
    return ruleStrategies[strategy].apply(null, params);
   })
  }
  
  /**
   * 检查已添加规则
   * @returns {{result: {Boolean},reason?: {String}}}
   */
  const check = () => {
   let validator = null;
   validatorCache.some(validatorFunc => {
    validator = validatorFunc();
    if(validator.result){
     $message.warning({
      content: validator.reason
     })
     return true;
    }
   })
   return validator;
  }
  return { addValidatorCache,check };
}
相关推荐
IT_陈寒1 天前
JavaScript性能优化:这7个V8引擎技巧让我的应用速度提升了50%
前端·人工智能·后端
学渣y1 天前
nvm下载node版本,npm -v查看版本报错
前端·npm·node.js
excel1 天前
首屏加载优化总结
前端
敲代码的嘎仔1 天前
JavaWeb零基础学习Day1——HTML&CSS
java·开发语言·前端·css·学习·html·学习方法
Tachyon.xue1 天前
Vue 3 项目集成 Element Plus + Tailwind CSS 详细教程
前端·css·vue.js
FuckPatience1 天前
Vue 中‘$‘符号含义
前端·javascript·vue.js
东风西巷1 天前
K-Lite Mega/FULL Codec Pack(视频解码器)
前端·电脑·音视频·软件需求
超级大只老咪1 天前
何为“类”?(Java基础语法)
java·开发语言·前端
你的人类朋友1 天前
快速搭建redis环境并使用redis客户端进行连接测试
前端·redis·后端
深蓝电商API1 天前
实战破解前端渲染:当 Requests 无法获取数据时(Selenium/Playwright 入门)
前端·python·selenium·playwright