复杂业务逻辑的判断与优化

news2024/11/19 18:39:23

作者 刘希忱 

在日常开发工作当中,优秀的用户界面数据库、构建工具、样式预处理器是前端现工作阶段必不可少的三大利器,很多优秀的团队已经为我们提供了很多便利的解决方案,但仍然有很多开发场景需要提升优化,比如声明、输出、判断、循环是开发过程当中最常见,也是我们用到最多的语法,简单语法逻辑在针对复杂的业务情况产生的同时也会变得繁琐且不易维护,此篇是对一些逻辑判断的优化思考。

案例参考

近日的公司需求 -> 满意度评价,这个案例大家很常见,不同的评分展示不同的内容,但是有些情况下评分不同,但是展示的内容相同,如下:

  • 0分:态度恶劣、方案不行、回复很慢、让我反复描述
  • 1分:态度敷衍、方案不行、回复慢、让我反复描述
  • 2分:态度一般、方案一般、回复慢、让我反复描述

传统实现方式

最省事的办法:

const scoreObj = {
  0: ['态度恶劣', '方案不行', '回复很慢', '让我反复描述'],
  1: ['态度敷衍', '方案不行', '回复慢', '让我反复描述'],
  2: ['态度一般', '方案一般', '回复慢', '让我反复描述']
}

上方的实现方式是最省事的,也是可能大家使用最多的开发方式,它的缺点也是显而易见的:重复的逻辑维护、大量的维护成本、多人开发涉及修改范围覆盖不全的问题

在和我司同事讨论当中,给出了一个新的方案,那就是把所有条件放到一个数组当中,通过条件的遍历来获取实际需求项

const scoreArr = ['态度恶劣', '方案不行', '回复很慢', '回复慢', '方案一般', '让我反复描述']
const condition = [ 1, 2 ]

// 伪代码,主要表达就是通过某些条件来获取实际要渲染的内容
const renderCondition = 1scoreArr.filter(item => condition.includes(item))

这也确实是一个办法,但是针对性场景相对来说较少,我们有多少的 scoreArr 就意味着我们每次的条件判断需要遍历多少遍,且每次 includes 也会再次遍历,那么这种写法的复杂度就是 m * n

最终实现方式

上图是整体的实现链路:

  • 拥有的业务参数进行附加到对应的条件中
  • 封装的方法获取对应条件的 code
  • 通过相应的 code 获取对应的条件
  • 获取对应的条件后判断是否存在该场景
  • 如果存在则执行相应场景的判断条件,否则返回不存在
  • 逻辑结束

实际代码

获取相应 code

首先,第一步要考虑的就是需要通过哪些条件去做判断,最终渲染出我们想要的内容:

getCode(code: number) {
  switch (code) {
    case 0:
      return this.zero;
    case 1:
      return this.one;
    case 2:
      return this.two;
    default:
      return '';
  }
}

上方的代码很简单,就是通过我们某些条件,来获取到我们对应的一个 命令 值

紧接着,在我们根据所有的条件依次拿到对应的 命令 以后,下一步就是我们要对这些条件去做一些对应的处理,让它们 “连” 起来:

getCondition(arr: string[]) {
  return arr.join('-');
}

获取对应条件

当我们获取到了最终的 条件,对于我们这个对象来说,它是一个 命令,针对当前对象的一个 命令,用来指挥我们当前对象应该去做什么事情:

getResult(condition: string) {
  if (this.map.has(condition)) {
    return this.map.get(condition) || function () {};
  }
  return function () {
    console.error(`条件 ${condition} 不存在对应方法`);
  };
}

通过 命令模式 的方式来将我的每一次需求发送到对应的 状态机 事件当中:

class {
  [x: string]: any;
  zero: string;
  map: Map<string, Function>;
  constructor() {
    this.zero = 'ZERO';
    // ...
    this.map = new Map([
      [
        'ZERO',
        () => {
          return [
            {
              label: '方案不行',
              value: '方案不行'
            }
          ];
        }
      ],
      // ...
    ]);
  }
}

完整代码

import ConditionController from './ConditionController';
const cacheConditionController = new ConditionController();

function getSelectorList(rateActive) {
  const code = cacheConditionController.getCode(rateActive);
  const condition = cacheConditionController.getCondition([code]);
  const config = cacheConditionController.getResult(condition)();
  const arr = [
    {
      label: '让我反复描述',
      value: '让我反复描述'
    }
  ];
  switch (rateActive) {
    case 0:
      return [
        {
          label: '态度恶劣',
          value: '态度恶劣'
        },
        ...config,
        {
          label: '回复很慢',
          value: '回复很慢'
        },
        ...arr
      ];
    case 1:
      return [
        {
          label: '态度敷衍',
          value: '态度敷衍'
        },
        ...config,
        ...arr
      ];
    case 2:
      return [
        {
          label: '态度一般',
          value: '态度一般'
        },
        {
          label: '方案一般',
          value: '方案一般'
        },
        ...config,
        ...arr
      ];
    default:
      return [];
  }
}

export default getSelectorList;

在实现过程当中,考虑到可能同一个业务需求当中,存在多个该场景,但是既然拆分了,就要拆分的清晰一些,不同的判断场景各自独立,这样可以保证我们在修复一些问题的时候,进行针对性的代码阅读,但是其中一些公共的处理方法又是可以通用的,例如 getCondition 和 getResult,所以我使用了 class 类继承的方式来实现该场景,一个完整的 高级多条件判断 实现如下:

// ConditionController.ts
import ConditionSuper from './ConditionSuper';

export default ConditionSuper(
  class {
    [x: string]: any;
    zero: string;
    one: string;
    two: string;
    four: string;
    five: string;
    map: Map<string, Function>;
    constructor() {
      this.zero = 'ZERO';
      this.one = 'ZERO-TWO';
      this.two = 'TWO';
      this.four = 'FOUR';
      this.five = 'FIVE';
      this.map = new Map([
        [
          'ZERO',
          () => {
            return [
              {
                label: '方案不行',
                value: '方案不行'
              }
            ];
          }
        ],
        [
          'ZERO-TWO',
          () => {
            return [
              ...this.getResult(this.getCode(0))(),
              ...this.getResult(this.getCode(2))()
            ];
          }
        ],
        [
          'TWO',
          () => {
            return [
              {
                label: '回复慢',
                value: '回复慢'
              }
            ];
          }
        ]
      ]);
    }

    getCode(code: number) {
      switch (code) {
        case 0:
          return this.zero;
        case 1:
          return this.one;
        case 2:
          return this.two;
        default:
          return '';
      }
    }
  }
);

// ConditionSuper.ts
function ConditionSuper(ExtendsParent: any) {
  return class extends ExtendsParent {
    getCondition(arr: string[]) {
      return arr.join('-');
    }

    getResult(condition: string) {
      if (this.map.has(condition)) {
        return this.map.get(condition) || function () {};
      }
      return function () {
        console.error(`条件 ${condition} 不存在对应方法`);
      };
    }
  };
}

export default ConditionSuper;

总结

上方的实现逻辑也只是未来可能遇见业务需求的一个缩影,实际情况可能比这个还要复杂,如果只靠单纯的 if (a === '***' && b > *** && c) 这类的判断条件来维护,并不是一个可观的解决方案,所以建议大家在开发过程当中,考虑使用该实现方案投入当项目当中去使用

可能会同学有这样的疑问,这样的拆分是否可以拆分成公共的方法去使用?

答案是不可以。在现在的开发环境当中,大家对于代码的拆分的理解日渐趋向于 拆分 === 公共方法 ,这其实完全是两码事,拆分的目的,其实是为了更好的去维护当前的项目,让大家在当前的项目当中去更好的阅读,更好的理解到我们当前需要理解到的业务,而并不是为了公共使用而去拆分。更何况,实际的判断条件是根据不同的业务条件去做的拆分的,怎么可能公共运用到不同的地方,除非业务场景和条件是 全覆盖 的

可能会同学有这样的疑问,那么这样写的代码量明显会增多了,这方面是怎么考虑的?

这确实是真实情况,代码量比直接 if 会增加很多 ,这就是我们实际需要去做取舍的地方了,如果我们是很简单的条件校验,不建议大家使用上面的方法,这样只会让我们的业务代码变得更多,考虑简单的条件、极限项目优化的角度来看,并不是太优秀,但是针对业务量庞大,且业务条件极度复杂,上面的条件虽然会带来更多的代码量,但是可以让我们更稳定的去运行当前的项目

这就好比小船(简单业务判断)和巨轮(极度复杂的大型项目),小船要的是在最短时间跑起来、跑得快,而不是去和巨轮去比谁功能全;巨轮和小船要比的是如何收益最大化、稳定运行,而不是比谁走出去的快

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1109520.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Cobalt Strike 钓鱼工具使用

免杀 安装 需要js环境 介绍 obalt Strike是一款基于java的渗透测试神器&#xff0c;常被业界人称为CS神器。自3.0以后已经不在使用Metasploit框架而作为一个独立的平台使用&#xff0c;分为客户端与服务端&#xff0c;服务端是一个&#xff0c;客户端可以有多个&#xff…

mysql varchar int

年龄是数字类型int SELECT * FROM test ORDER BY age; 年龄是字符类型varchar SELECT * FROM test ORDER BY code; 第1种 补前导0可以和数字一样排序 MySQL会比较字符的ASCII值&#xff0c;并根据这些值来确定字符的排列顺序。 印象中oracle好像也是吧。 ASCII (American …

【yolov8目标检测】使用yolov8训练自己的数据集

目录 准备数据集 python安装yolov8 配置yaml 从0开始训练 从预训练模型开始训练 准备数据集 首先得准备好数据集&#xff0c;你的数据集至少包含images和labels&#xff0c;严格来说你的images应该包含训练集train、验证集val和测试集test&#xff0c;不过为了简单说…

2023年10月中国数据库排行榜:墨天轮榜单前五开新局,金仓、亚信热度攀升

怀鸿鹄之志&#xff0c;展骐骥之跃。 2023年10月的 墨天轮中国数据库流行度排行 火热出炉&#xff0c;本月共有286个数据库参与排名。本月排行榜前十名变动较大&#xff0c;**华为 openGauss 重归探花之位&#xff0c;人大金仓 KingBase 热度上升&#xff0c;亚信 AntDB 进军10…

开源软件-禅道Zentao

禅道Zentao 简介漏洞复现SQL注入漏洞**16.5****router.class.php SQL注入** **v18.0-v18.3****后台命令执行** 远程命令执行漏洞&#xff08;RCE&#xff09;后台命令执行 简介 是一款开源的项目管理软件&#xff0c;旨在帮助团队组织和管理他们的项目。Zentao提供了丰富的功能…

Spring Security—Servlet 应用架构

目录 一、Filter&#xff08;过滤器&#xff09;回顾 二、DelegatingFilterProxy 三、FilterChainProxy 四、SecurityFilterChain 五、Security Filter 六、打印出 Security Filter 七、添加自定义 Filter 到 Filter Chain 八、处理 Security 异常 九、保存认证之间的…

关于统信UOS不能使用“modprobe brd”创建内存盘的问题

前言 我自用的电脑内存都比较大&#xff0c;因此很早就养成了使用内存做临时盘的习惯 内存盘的好处很多&#xff0c;比如将系统临时文件夹、浏览器缓存文件等设置到内存盘&#xff0c;不仅可以提升速度&#xff0c;还可以减少对固态硬盘的写入&#xff0c;提升固态盘的使用寿…

金融机器学习方法:回归分析

回归分析是统计学中的一个重要分支&#xff0c;它用于建立一个或多个自变量和一个因变量之间的关联模型。在本博客中&#xff0c;我们将深入探讨线性回归和逻辑回归这两种常见的回归分析方法&#xff0c;并通过Python示例进行分析。 目录 1.线性回归1.1 模型介绍1.2 示例分析 …

使用STM32怎么喂狗 (IWDG)

STM32F1 的独立看门狗&#xff08;以下简称 IWDG&#xff09;。 STM32F1内部自带了两个看门狗&#xff0c;一个是独立看门狗 IWDG&#xff0c;另一个是窗口看门狗 WWDG&#xff0c; 本章只介绍独立看门狗 IWDG&#xff0c;窗口看门狗 WWDG 会在后面章节介绍。 本章要实现的功能…

吉利银河L6征战2023混合动力汽车极限挑战赛获双冠,同级“优等生”不负众望

9月22-9月27日&#xff0c;由中汽信科携手昆明检验中心联合发起的国内首个混动汽车专属赛事2023混合动力汽车极限挑战赛在云南圆满结束。比赛项目涉及纯电续航里程、亏电油耗、高速真实能耗、高原山地极限能耗等多项衡量混动车买点的关键指标。在为期六天的挑战中&#xff0c;这…

java SpringBoot+Vue3打造企业级一体化SaaS系统视频课程,开发ERP与CRM系统实用课程(免费领取)

java SpringBootVue3打造企业级一体化SaaS系统视频课程&#xff0c;开发ERP与CRM系统实用课程&#xff08;免费领取&#xff09; &#xff1a; 查看文末领取课程 第1章 课程导学 1-1 、导学&#xff08;课程简介、ERP与CRM融合成为大趋势&#xff09; 1-2 、课程学习方法&am…

跨境电商商城源码(多语言多商户进出口电商平台)

一、跨境电商商城系统源码包括以下几个部分 前端框架&#xff1a;uni-app,vue 后端框架&#xff1a;ThinkPHP5.wokerman 支付系统&#xff1a;PayPal、USDT等主流支付平台 语言包&#xff1a;跨境电商支持15种语言&#xff0c;后续会增加 前端&#xff1a;包含APP端、小程序端、…

半主动悬架系统开发与测试(基于Modelbase实现)

ModelBase是经纬恒润开发的车辆仿真软件&#xff0c;包含两个大版本&#xff1a;动力学版本、智能驾驶版本。动力学版包含高精度动力学模型&#xff0c;能很好地复现车辆在实际道路中运行的各种状态变化&#xff0c;可用于乘用车、商用车动力底盘系统算法开发、控制器仿真测试&…

竞赛 深度学习乳腺癌分类

文章目录 1 前言2 前言3 数据集3.1 良性样本3.2 病变样本 4 开发环境5 代码实现5.1 实现流程5.2 部分代码实现5.2.1 导入库5.2.2 图像加载5.2.3 标记5.2.4 分组5.2.5 构建模型训练 6 分析指标6.1 精度&#xff0c;召回率和F1度量6.2 混淆矩阵 7 结果和结论8 最后 1 前言 &…

10_18Qt

头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QMovie> #include<QDebug> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr)…

35 机器学习(三):混淆矩阵|朴素贝叶斯|决策树|随机森林

文章目录 分类模型的评估混淆矩阵精确率和召回率 接口介绍其他的补充 朴素贝叶斯基础原理介绍拉普拉斯平滑下面给出应用的例子朴素贝叶斯的思辨 决策树基础使用基本原理信息熵信息增益信息增益率Gini指数 剪枝api介绍 随机森林------集成学习初识基本使用api介绍 分类模型的评估…

基础设施SIG月度动态:T-One 社区版调度引擎全量替换至 runnerV2 版本,调度性能平均提升 6.8 倍

基础设施 SIG&#xff08;OpenAnolis Infra SIG&#xff09;目标&#xff1a;负责 OpenAnolis 社区基础设施工程平台的建设&#xff0c;包括官网、Bugzilla、Maillist、ABS、ANAS、CI 门禁以及社区 DevOps 相关的研发工程系统。 01 SIG 整体进展 1.官网 SIG 外链跳转增加确认…

List执行remove操作间歇性报错UnsupportedOperationException

废话不多说&#xff0c;直接上一个代码&#xff0c;意思很简单&#xff0c;就是把list中的"全部"置顶&#xff0c;但是不知道怎么会偶发报错。 List<UserDept> voList new ArrayList<>(userGroupService.findByName(groupName));for(UserDept userDept…

点云相关内容总结

点云相关内容总结 地形相关内容1. 机载点云地面点和非地面点识别 地形相关内容 1. 机载点云地面点和非地面点识别 识别场景中的梯度较大的区域&#xff0c;进行渐进三角网滤波&#xff0c;梯度大的地方补一下初始地面点 与其他软件相关算法结果进行对比 软件1 三角网滤波算…

塑料透光率测试可测试塑料部件的透明度和纯度

随着电子设备的快速发展&#xff0c;尤其是智能手机、平板电脑、可穿戴设备等新兴产品的普及&#xff0c;对塑料材料的需求量也在逐渐增加。因为这些电子设备需要大量的塑料材料来制造外壳、内部结构、部件等。电子设备在塑料行业的发展迅速&#xff0c;推动了塑料材料的技术进…