🙅‍都说太多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
1567 0
【微服务33】分布式事务Seata源码解析一:在IDEA中启动Seata Server
|
4月前
|
存储 人工智能 自然语言处理
AI代理内存消耗过大?9种优化策略对比分析
在AI代理系统中,多代理协作虽能提升整体准确性,但真正决定性能的关键因素之一是**内存管理**。随着对话深度和长度的增加,内存消耗呈指数级增长,主要源于历史上下文、工具调用记录、数据库查询结果等组件的持续积累。本文深入探讨了从基础到高级的九种内存优化技术,涵盖顺序存储、滑动窗口、摘要型内存、基于检索的系统、内存增强变换器、分层优化、图形化记忆网络、压缩整合策略以及类操作系统内存管理。通过统一框架下的代码实现与性能评估,分析了每种技术的适用场景与局限性,为构建高效、可扩展的AI代理系统提供了系统性的优化路径和技术参考。
229 4
AI代理内存消耗过大?9种优化策略对比分析
|
8月前
|
SQL 容灾 关系型数据库
阿里云DTS踩坑经验分享系列|DTS打通SQL Server数据通道能力介绍
SQL Server 以其卓越的易用性和丰富的软件生态系统,在数据库行业中占据了显著的市场份额。作为一款商业数据库,外部厂商在通过解析原生日志实现增量数据捕获上面临很大的挑战,DTS 在 SQL Sever 数据通道上深研多年,提供了多种模式以实现 SQL Server 增量数据捕获。用户可以通过 DTS 数据传输服务,一键打破自建 SQL Server、RDS SQL Server、Azure、AWS等他云 SQL Server 数据孤岛,实现 SQL Server 数据源的流动。
463 0
阿里云DTS踩坑经验分享系列|DTS打通SQL Server数据通道能力介绍
|
运维 Prometheus 监控
运维中的自动化工具与实践指南
本文深入探讨了自动化工具在IT运维中的重要性,提供了多种实用工具的推荐与应用实例。通过分析自动化工具如何提升运维效率、减少错误率,我们将揭示其在现代信息技术管理中的核心价值。无论你是IT新手还是经验丰富的专家,都能从中汲取到有益的知识,进而提升你的工作效果。
|
编解码 计算机视觉 索引
使用ffmpeg MP4转 m3u8并播放 实测!!
使用ffmpeg MP4转 m3u8并播放 实测!!
938 1
|
Python
Python办公自动化之Excel转Word
Python办公自动化之Excel转Word
547 0
|
SQL 数据库
SQL JOIN 子句:合并多个表中相关行的完整指南
SQL LEFT JOIN关键字返回左表(table1)中的所有记录以及右表(table2)中的匹配记录。如果没有匹配,则右侧的结果为0条记录。
587 0
|
人工智能 达摩院 异构计算
阿里巴巴的AI实首发人工智能全阵型,平头哥、达摩院、阿里云三位一体
9月26日,阿里巴巴在杭州云栖大会上首次公布人工智能调用规模:每天调用超1万亿次,服务全球10亿人,日处理图像10亿张、视频120万小时、语音55万小时及自然语言5千亿句,已经成为中国最大的人工智能公司。
|
SQL Cloud Native Java
分布式事务Seata源码解析八:本地事务执行流程(AT模式下)
分布式事务Seata源码解析八:本地事务执行流程(AT模式下)
952 0
分布式事务Seata源码解析八:本地事务执行流程(AT模式下)
|
Java 关系型数据库 数据库
32-微服务技术栈(高级):分布式事务Seata的TCC模式
在分布式架构系统中,服务不止一个,一个完整的业务链路肯定也不止调用一个服务,此时每个服务都有自己的数据库增删改查,而每一个写操作对应一个本地事务。如果想要确保全部的业务状态一致,也就意味着需要所有的本地事务状态一致,这在我们之前的学习中肯定是不具备的,如何做到跨服务、跨数据源的事务一致性将是本章节的重点学习内容。
502 0