🙅‍都说太多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 语句的问题。如果你有任何疑问或者想进一步讨论相关话题,请随时告诉我。🚀✨

目录
相关文章
|
存储 SpringCloudAlibaba Cloud Native
【微服务33】分布式事务Seata源码解析一:在IDEA中启动Seata Server
【微服务33】分布式事务Seata源码解析一:在IDEA中启动Seata Server
1722 0
【微服务33】分布式事务Seata源码解析一:在IDEA中启动Seata Server
|
消息中间件 Kafka 数据处理
实时数据流处理:Dask Streams 与 Apache Kafka 集成
【8月更文第29天】在现代数据处理领域,实时数据流处理已经成为不可或缺的一部分。随着物联网设备、社交媒体和其他实时数据源的普及,处理这些高吞吐量的数据流成为了一项挑战。Apache Kafka 作为一种高吞吐量的消息队列服务,被广泛应用于实时数据流处理场景中。Dask Streams 是 Dask 库的一个子模块,它为 Python 开发者提供了一个易于使用的实时数据流处理框架。本文将介绍如何将 Dask Streams 与 Apache Kafka 结合使用,以实现高效的数据流处理。
426 0
|
编解码 计算机视觉 索引
使用ffmpeg MP4转 m3u8并播放 实测!!
使用ffmpeg MP4转 m3u8并播放 实测!!
1104 1
|
Python
Python办公自动化之Excel转Word
Python办公自动化之Excel转Word
622 0
|
人工智能 达摩院 异构计算
阿里巴巴的AI实首发人工智能全阵型,平头哥、达摩院、阿里云三位一体
9月26日,阿里巴巴在杭州云栖大会上首次公布人工智能调用规模:每天调用超1万亿次,服务全球10亿人,日处理图像10亿张、视频120万小时、语音55万小时及自然语言5千亿句,已经成为中国最大的人工智能公司。
|
SQL 数据库
SQL JOIN 子句:合并多个表中相关行的完整指南
SQL LEFT JOIN关键字返回左表(table1)中的所有记录以及右表(table2)中的匹配记录。如果没有匹配,则右侧的结果为0条记录。
615 0
|
SQL Cloud Native Java
分布式事务Seata源码解析八:本地事务执行流程(AT模式下)
分布式事务Seata源码解析八:本地事务执行流程(AT模式下)
1025 0
分布式事务Seata源码解析八:本地事务执行流程(AT模式下)
|
Java 关系型数据库 数据库
32-微服务技术栈(高级):分布式事务Seata的TCC模式
在分布式架构系统中,服务不止一个,一个完整的业务链路肯定也不止调用一个服务,此时每个服务都有自己的数据库增删改查,而每一个写操作对应一个本地事务。如果想要确保全部的业务状态一致,也就意味着需要所有的本地事务状态一致,这在我们之前的学习中肯定是不具备的,如何做到跨服务、跨数据源的事务一致性将是本章节的重点学习内容。
559 0
【UCIe】UCIe Clock Gating
【UCIe】UCIe Clock Gating
942 0
【UCIe】UCIe Clock Gating
|
存储
Win10下破解 Idea2021.2 修改idea.vmoptions 导致IDEA 无法启动
Win10下破解 Idea2021.2 修改idea.vmoptions 导致IDEA 无法启动
1632 0
Win10下破解 Idea2021.2 修改idea.vmoptions 导致IDEA 无法启动