🙅‍都说太多if...else不好,那有没有可以直接抄的改造方案呢?

简介: 开发过程中,经常遇到大量的if...else逻辑,这使得代码复杂、难以维护。但别担心!这里会引导你走出这个困境!

嗨,大家好!这里是道长王jj~ 🎩🧙‍♂️

日常的代码审查工作总是会带来各种惊喜🎁,尤其当你遇到那些让你眼前一黑的代码。

比如我在上次的审查中,看到我们的小明同事在他的JavaScript代码中堆砌了一个看起来就像一座大山的超过20个的 if...else 语句。类似下面这样:

function calculatePrice(type, basePrice) {
   
    if (type === 'student') {
   
        return basePrice * 0.8;
    } else if (type === 'senior') {
   
        return basePrice * 0.7;
    } else if (type === 'veteran') {
   
        return basePrice * 0.75;
    } 
    // 这个列表有20多个条件,我们在这里省略...
    else {
   
        return basePrice;
    }
}

🙅‍♂️ 为何不推荐大量的 if...else

咳咳,看到这里,让我想起了小时候堆积木游戏,每堆一个积木都充满了危险和快感。但这样的代码确实存在一些问题,比如:

  1. 阅读困难:就像尝试阅读一篇只有一个长长的段落的小说,你需要花费大量的时间和精力去理解它。
  2. 高维护成本:想象一下,如果需要在中间插入一个新的条件,你需要找到正确的位置,然后小心翼翼地插入新的 if...else 语句。
  3. 可扩展性差:对于特殊的需求,例如动态的添加新的折扣类型,你可能需要大量的修改和测试。

作为一名合格的开发者,我们总是希望自己能写出优雅、可读性高、易维护的代码。于是,让我们看看有没有其他方法能替代这个冗长的 if...else 呢?😉

❗注意!不是说所有的if…else都要被替代

重构代码的目的是为了提高代码的可读性、可维护性和扩展性。

但并不是所有的if...else语句都应该被替代或重构!

如果你的代码里是以下的情况,就不要想着重构炫技啦!

  1. 简单的条件分支:如果代码中的if...else语句仅有一到两个简单的条件分支,没必要改。
  2. 高度相关的逻辑分支:复杂的逻辑,如果被分解成多个独立的函数或对象,会失去逻辑的连贯性和上下文含义,你也不想代码看不懂吧!

👏 项目案例:函数式编程+设计模式替代 if...else

注意:以下的代码都有意地在使用JavaScript的对象字面量,可以使代码更加干净和易于阅读。这是一种函数式编程的方式。

设计模式是为了解决一些特定问题而提出的代码结构,它能帮助我们更好地组织代码,提高代码的可读性和可维护性。按照水文掘金老套路。我先介绍一下有哪几种常见的设计模式可以优化这类问题。

策略模式

策略模式定义了一系列的算法,并将每一个算法封装起来,使它们可以互相替换。在 JavaScript 中,我们可以使用对象来实现策略模式,这也是最简单的改造,就像下面这样:

const strategies = {
   
    'student': (basePrice) => {
   
        return basePrice * 0.8;
    },
    'senior': (basePrice) => {
   
        return basePrice * 0.7;
    },
    'veteran': (basePrice) => {
   
        return basePrice * 0.75;
    },
    'default': (basePrice) => {
   
        return basePrice;
    }
}const calculatePrice = (type, basePrice) => {
   
    return (strategies[type] || strategies['default'])(basePrice);
}
calculatePrice('student', 1) // 输出: 0.8

如果是面对多层嵌套呢?

对于多层嵌套的if...else,我们同样可以通过使用策略模式来改善代码的可读性和维护性。只是说我们把判断逻辑放在了独立的函数中。

假设我们现在有一个需求,即根据用户的类型和他们的购买量来计算折扣。如果用户是学生,购买量大于10个,他们可以享受8折优惠;如果用户是老年人,购买量大于20个,他们可以享受7折优惠。

const strategies = {
   
    'student': quantity => quantity > 10 ? 0.8 : 1,
    'senior': quantity => quantity > 20 ? 0.7 : 1,
    'default': () => 1
};const calculate = (type, quantity) => {
   
    return (strategies[type] || strategies['default'])(quantity)
}
calculate('student', 15) // 输出: 0.8

这样一来,我们的代码就变得更加清晰和易读了。而且如果我们想添加新的策略,只需要在 strategies 对象中添加新的属性和函数就可以了。

工厂模式

其实这个我都有点不愿意讲了,因为上一个例子中其实本身也是一种工厂模式的实现,这一次我们要把那个例子转换为一个更明显的工厂模式,我们可以将函数calculate转换为一个工厂函数,它创建并返回一个对象,这个对象有一个calculate方法:

const strategies = {
   
    'student': quantity => quantity > 10 ? 0.8 : 1,
    'senior': quantity => quantity > 20 ? 0.7 : 1,
    'default': () => 1
};const createCalculator = (type) => {
   
    return {
   
        calculate: (quantity) => (strategies[type] || strategies['default'])(quantity)
    }
}const studentCalculator = createCalculator('student');
studentCalculator.calculate(15); // 输出: 0.8

查找表模式

查找表模式其实是策略模式的一种简化形式,它更像是一个简单的映射表。我们可以把所有的策略映射到一个对象中,然后通过键来查找对应的策略。对于上面的例子而言,本质只是改变了存储方式,我们使用映射表来保存策略就行了(是不是突然觉得也没有那么高大上了哈哈😄):

const studentStrategy = quantity => quantity > 10 ? 0.8 : 1;
const seniorStrategy = quantity => quantity > 20 ? 0.7 : 1;
const defaultStrategy = () => 1;const strategies = {
   
    'student': studentStrategy,
    'senior': seniorStrategy,
    'default': defaultStrategy
};const calculate = (type, quantity) => {
   
    return (strategies[type] || strategies['default'])(quantity)
}calculate('student', 15); // 输出: 0.8

职责链模式

职责链模式是一种对象的行为模式,在这种模式中,每一个对象都有机会处理请求,从而解除了发送者和接收者之间的耦合关系。在JavaScript中,我们可以用链式调用来实现职责链模式:

// 学生条件进入
const studentHandler = (type, quantity, next) => {
   
    if (type === 'student' && quantity > 10) {
   
        return 0.8;
    }
    return next(type, quantity);
};
// 军人条件进入
const seniorHandler = (type, quantity, next) => {
   
    if (type === 'senior' && quantity > 20) {
   
        return 0.7;
    }
    return next(type, quantity);
};
// 没有特殊条件时进入
const defaultHandler = (type, quantity, next) => {
   
    return 1;
};// 定义一个函数,这个函数会生成一个处理器链
const createHandlerChain = (...handlers) => (type, quantity) => {
   
    let index = 0;
    const next = (type, quantity) => {
   
        if (index < handlers.length) {
   
            return handlers[index++](type, quantity, next);
        }
    };
    return next(type, quantity);
};// 组合函数
const calculate = createHandlerChain(studentHandler, seniorHandler, defaultHandler);calculate('student', 15)
; // 输出: 0.8

各类设计模式和最佳实践能运用到实际项目中(复制粘贴,嘿嘿),对我们一定有不小地进步!

🎉 希望本文能够帮助你解决优化大量的 if...else 语句的问题。如果你有任何疑问或者想进一步讨论相关话题,请随时告诉我。🚀✨

目录
相关文章
|
8月前
|
SQL 安全 前端开发
Web安全性测试包括哪些要点?梳理下,总算搞明白了
Web安全性测试包括哪些要点?梳理下,总算搞明白了
178 0
Web安全性测试包括哪些要点?梳理下,总算搞明白了
|
12月前
|
消息中间件 缓存 NoSQL
用一个月重构了同事写的烂代码,我总结了8条重写烂代码的经验!
用一个月重构了同事写的烂代码,我总结了8条重写烂代码的经验!
|
编译器 C++
还在因为写项目函数太多而烦恼?C++模板一文带你解决难题
还在因为写项目函数太多而烦恼?C++模板一文带你解决难题
|
设计模式 SQL Java
有点狠有点猛,我用责任链模式重构了业务代码
文章开篇,抛出一个老生常谈的问题,学习设计模式有什么作用? 设计模式主要是为了应对代码的复杂性,让其满足开闭原则,提高代码的扩展性 另外,学习的设计模式 一定要在业务代码中落实,只有理论没有真正实施,是无法真正掌握并且灵活运用设计模式的 这篇文章主要说 责任链设计模式,认识此模式是在读 Mybatis 源码时, Interceptor 拦截器主要使用的就是责任链,当时读过后就留下了很深的印象(内心 OS:还能这样玩)
|
移动开发 前端开发 小程序
不愧是前端老油条,分分钟看出我方案的bug
国庆前刚开发完一个小需求,常规性的做了一次code review,不过这次review有所不同,我们组前端老油条竟然参会了,平时发会邀都不来的。 不过不愧是老油条,竟然分分中发现了问题,老油条的地位又在我们小前端的心里巩固了一下。 和往常一样,review前先过一遍技术方案,一让大家快速的了解需求,二来分析下技术方案是否存在问题,是否合理,一般情况下,技术方案没问题,后面的代码review感觉就没啥必要了,因为很少有人听。
114 0
不愧是前端老油条,分分钟看出我方案的bug
|
开发框架 Java 测试技术
【测试基础】五、这样提bug单,开发小哥还会怼你么?
【测试基础】五、这样提bug单,开发小哥还会怼你么?
【测试基础】五、这样提bug单,开发小哥还会怼你么?
|
运维 监控 前端开发
程序员告别 996 第一步:1 人搞定一个项目,摆脱“重复造轮子”
程序员告别 996 第一步:1 人搞定一个项目,摆脱“重复造轮子”
210 0
程序员告别 996 第一步:1 人搞定一个项目,摆脱“重复造轮子”
|
SQL 运维 监控
线上高并发应用重构(写)填坑经验分享(一)
今年在公司重构(写)了一个老项目,踩了无数的坑。 中间好几次遇到问题,甚至感觉项目可能要失败了,好在最后终于成功上线了。 虽然被坑的不要不要的,但也从中领悟到了不少东西,在这里记录一下,顺便分享给大家乐呵乐呵。 先简单介绍下项目,一个面向C端用户的服务,主要提供包括动态、评论、圈子、好友、关注、Feed等常见的社区功能,另外还有其他一些个性化的功能。 日活比较高,整个服务QPS上万。高频业务,单个接口QPS上千。单项业务数据量过亿,比如评论。
线上高并发应用重构(写)填坑经验分享(一)
|
前端开发 JavaScript 算法
这些前端案例看似很简单(内附动图)
前言 在学习前端js操作元素的时候,往往有很多的案例的做法的思想都是一样的,我们一定要会。本篇文章将从几个小demo入手,带你领略js的风采。 很常见的一些案例,一定要学会哦!!!
134 0
这些前端案例看似很简单(内附动图)
如何做好游戏陪玩源码的功能优化,这三步缺一不可
如何做好游戏陪玩源码的功能优化,这三步缺一不可