我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何删掉编程中的 Switch 语句

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何删掉编程中的 Switch 语句

多重方法是一种有趣的方式,可以帮你摆脱令人讨厌的 switch。而且,这也有助于提升代码的可读性。所以,在决定继续坚持使用 switch 之前,一定要先试一试。

本文最初发布于 Bits and Pieces。

很多开发者都讨厌switch语句,包括我。并不是因为这个语句没用,也不是因为它太难了。

理解switch语句的工作原理非常简单,问题是当你真的遇到它时,就必须停下手头的一切工作,集中精力阅读它,以确保不会遗漏任何东西,比如,缺少break语句可能会导致一些意想不到的行为,或者一个case中大约有 20 行代码。

关键是,原谅我使用一个花哨的术语:理解switch语句(在现实世界中)所需要的认知负荷相当重。我相信,作为开发人员,我们的目标是编写方便人类阅读的代码。在这方面,这个语句提供不了什么帮助。

但是,我写这篇文章不是为了对它进行抨击,我是要向你(之前也包括我)展示三个关于如何避免使用switch语句的示例,让我们来看一种函数式编程技术:多重方法。

什么是多重方法?

我第一次听到这个词,还是在播客“20 MinJS”中采访 Yehonathan Sharvit 时。当时的采访是关于他即将由 Manning 出版的著作《面向数据的编程》。

他提出这一概念是为了从功能上取代继承,这无疑是可行的。在这个过程中,他展示了switch语句是如何被取代的。因此,让我们暂时把 OOP 放在一边,只关注第二部分:消除代码中丑陋的switch

什么是多重方法?它只是一个能够根据接收到的参数选择最佳实现的函数。换句话说,想象一下,如果你把丑陋的switch语句放在函数中,然后对所有人隐藏实现。

唯一的区别是,你的解决方案只适用于一个函数。今天我们将讨论如何在运行中生成多个多重方法。

多重方法是什么样子?

当然,每种语言都有自己的变体,但我今天主要讲 JavaScript。

在这种语言中,多重方法的使用方法如下:

//我们将使用的数据
const myDog = {
    type: "dog",
    name:"Robert"
}
const myCat = {
    type: "cat",
    name: "Steffan"
}
//自定义函数实现
function greetDogs (dog) {
    console.log("Hello dear Dog, how are you today", dog.name, "?")
}
function greetCats(cat) {
    console.log("What's up", cat.name, "?")
}
//定义我们的多重方法
let greeter = null
greeter = multi(
    animal => animal.type,
    method("dog", greetDogs),
    method("cat", greetCats)
)(greeter)
// 调用多重方法
greeter(myDog)
greeter(myCat)

这个例子做了很多事,让我来说明下:

  • 我定义了 2 个对象myCatmyDog,我将把它们作为参数,多重方法将根据它们确定自己的行为。

  • 我定义了 2 个自定义函数greetDogsgreetCats,它们的实现稍有不同。它们将代表switch中每个case语句里的代码。

  • 然后我调用一些函数,尤其是multimethod,来定义多重方法greetermulti函数接收 3 个属性:一个分配器(dispatcher),我们将用它返回的值来确定要执行的逻辑片段;还有两个方法,分别代表switch的一个case语句。请注意,每次调用method时,要首先指定触发第二个参数的值(这是实际的逻辑所在)。

  • 最后,我使用同一个函数(我的多重方法)来执行两个不同的逻辑片段,而不需要在任何地方使用switchif语句。

多重方法有什么好处?

当然,我们在这里没有施展任何类型的魔法,我们只是重写了决策逻辑的表达方式,类似下面这样的switch语句:

switch(animal.type) {
  
  case "dog":
    greetDogs(animal);
  break;
  case "cat":
    greetCats(animal);
 break;
}

那么,如果我们可以直接这样做,为什么还要大费周章地使用多重方法呢?问题的关键是可读性。

switch语句非常开放,显示了我们的决策逻辑的实现。换句话说,这个语句是命令式的。它向你展示了决策树的内部运作情况,这意味着阅读代码的人将不得不在头脑中解析代码。因此,我们又回到了认知负荷的概念。这使得开发者要阅读并在头脑中解析代码。

你要知道,大多数开发人员在遇到像上面这样的switch时,不会有什么反应。但是,这也不是一个实际的例子。通常情况下,case语句包含的代码更多,也更难阅读。

而多重方法隐藏了决策逻辑的内部结构,你所知道的只是你对它做了设置,它将以某种方式工作。你更关心的是功能而不是实际的实现。这被称为“声明式编程”,有助于提高代码的可读性,同时降低开发人员的认知负担。这是因为它在逻辑上增加了一层抽象,为我们提供了更接近人类语言的表达工具。

如果这还不能说服你,还有一个优点:可扩展性。

如果你需要在switch中添加另一个选项,就必须回到代码中修改同一个switch,如果你,比如说,碰巧忘记添加break语句,就有可能造成问题,就像下面这样:

switch(animal.type) {
  case "rabbit":
    greetRabbits(animal);
  case "dog":
    greetDogs(animal);
  break;
  case "cat":
    greetCats(animal);
 break;
}

还是个非常简单的例子,但如果是真实世界中一段更长的代码,那么这种情况出现的几率就更大了。

以防你对这种行为不熟悉,请让我做个说明。第一个case中缺失break,会导致在动物类型为“rabbit”时也执行第二个case下的逻辑。

然而,有了多重方法,我们就可以不断地根据需要对它进行扩展:

let extendedGreeter = multi(
    animal => animal.type,
    method("parrot", sayHiParrot)
)(greeter)

现在,这个新方法extendedGreeter对“dog”、“cat“、”parrot“就都有效了,而我们不必再回去修改已有的代码。

这是一个很大的好处,因为我们都知道,每次我们触碰可以正常工作的代码时,都有一点可能引入 Bug。在这里,我们把可能性降低到 0。

实现一个多重方法库

首先,你要知道,已经有一些库在处理这个问题了,其中一个例子是@arrows/multimethod。

尽管如此,对这些实现进行逆向工程总是很有趣,所以让我们看一看如何实现一个基本的多重方法库,以适应到目前为止所展示的例子。

理解这个问题的关键是,我们需要一个分配器函数来给提供一个实际的值,我们将用它作为判断执行哪个方法的键。而且,我们不能对switch语句进行硬编码,因为选项的数量是不固定的。

不能光说不练,下面是实现:

function method(value, fn) {
    return {value, fn}
}
function multi(dispatcher, ...methods) {
    return (originalFn) => {
        return (elem) => {
            let key = dispatcher(elem)
            let method = methods.find( m => m.value === key)
            if(!method) {
                if(originalFn) {
                    return originalFn(elem)
                } else {
                    throw new Error("No sure what to do with this option!")
                }
            }
            return method.fn(elem)
        }
    }
}

method函数只是把键和实际的逻辑耦合在一起,没有别的。multi函数中的代码才有趣,它返回一个匿名函数,以原始函数为参数并返回一个新函数,后者根据分配器代码(我们的第一个参数)返回的值执行不同的东西。

让我们逐行看下:

  • 首先,调用第 8 行的函数时提供一个属性(比方说myDog)。

  • 第 9 行的分配器逻辑会获取myDog并返回其类型,即“dog”。

  • 然后在第 10 行,我们找到第一个与该类型匹配的方法。

  • 如果没有方法匹配,但我们有一个有效的“originalFn”(也就是说,我们正在扩展一个原始的多重方法),我们会让它来处理这种情况。否则,我们将抛出一个异常,因为我们对此无能为力。

  • 然而,如果找到了匹配的方法,就在第 18 行执行它,并将原始属性“myDog”传递给它。

就是这样。没那么复杂,对吗?当然,如果你想提供“默认”情况处理而不是抛出一个异常,或者你想处理多属性决策(比如根据属性typename决定逻辑,而不是只根据第一个属性),就得编写更多的代码了。

不过,还是那句话,如果你打算使用多重方法,建议你使用一个现有的库,而不是自己去实现。

多重方法是一种有趣的方式,可以帮你摆脱令人讨厌的switch。而且,这也有助于提升代码的可读性。所以,既然你已经了解了多重方法,那么在决定继续坚持使用switch之前,一定要先试一试。

到此这篇关于如何删掉编程中的 Switch 语句的文章就介绍到这了,更多相关Switch 语句删掉内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何删掉编程中的 Switch 语句

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C#中如何使用Switch语句

这期内容当中小编将会给大家带来有关C#中如何使用Switch语句,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。C# Switch语句这个语句求一个表达式的值,并将这个值与许多case进行比较。每个case
2023-06-18

PHP中如何使用Switch语句

这篇文章将为大家详细讲解有关PHP中如何使用Switch语句,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。PHP Switch语句工作原理:对表达式(通常是变量)进行一次计算 把表达式的值与
2023-06-17

C++中如何使用switch-case语句

今天就跟大家聊聊有关C++中如何使用switch-case语句,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。if语句处理两个分支,处理多个分支时需使用if-else-if结构,但如果
2023-06-17

Java中Switch条件语句如何使用

Java中Switch条件语句如何使用,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、switch条件语句1.switch是一个很常用的选择语句,和if语句不一样,它是对某个
2023-06-16

如何在Python中实现真正的switch-case语句

这篇文章给大家分享的是有关如何在Python中实现真正的switch-case语句的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在 Python 中实现真正的 switch-case 语句。这是使用字典来模仿 s
2023-06-27

java中switch语句的执行过程是什么

今天就跟大家聊聊有关java中switch语句的执行过程是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Java的特点有哪些Java的特点有哪些1.Java语言作为静态面向对象编
2023-06-14

PHP中如何使用MySQL删除语句

今天小编给大家分享一下PHP中如何使用MySQL删除语句的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、MySQL删除语句
2023-07-05

如何实现MySQL中删除用户的语句?

如何实现MySQL中删除用户的语句?MySQL是一种流行的关系数据库管理系统,常用于存储和管理大量数据。在日常使用中,我们可能需要删除不再需要的用户。本文将介绍如何在MySQL中使用具体的代码示例删除用户。在MySQL中,我们可以通过使用D
如何实现MySQL中删除用户的语句?
2023-11-08

如何实现MySQL中删除数据的语句?

如何实现MySQL中删除数据的语句?数据库管理系统中,删除数据是常见的操作之一。MySQL作为一款常用的关系型数据库管理系统,提供了简单且有效的删除数据的语句。在本文中,我们将讨论如何实现MySQL中删除数据的语句,包括具体的代码示例和一些
如何实现MySQL中删除数据的语句?
2023-11-08

如何实现MySQL中删除索引的语句?

如何实现MySQL中删除索引的语句?在MySQL中,索引是提高查询性能的重要工具之一。然而,有时候我们需要删除某个表的索引,可能是因为索引不再使用或者需要重新设计。本文将介绍如何在MySQL中删除索引的语句,并给出具体的代码示例。在MySQ
如何实现MySQL中删除索引的语句?
2023-11-08

如何实现MySQL中删除视图的语句?

如何实现MySQL中删除视图的语句?视图是MySQL中一种虚拟表,它是基于查询结果的表。在某些情况下,我们可能不再需要某个视图或者需要重新定义视图结构,这时就需要删除视图。那么,接下来我将介绍如何在MySQL中使用删除视图的语句,以及提供具
如何实现MySQL中删除视图的语句?
2023-11-08

如何实现MySQL中删除数据库的语句?

MySQL是一种常用的关系型数据库管理系统,它提供了许多操作数据库的SQL语句。其中,删除数据库的语句是经常用到的,本文将为大家介绍如何实现MySQL中删除数据库的语句,并提供具体的代码示例。删除空数据库首先,我们来介绍如何删除一个空数据库
如何实现MySQL中删除数据库的语句?
2023-11-08

如何实现MySQL中删除触发器的语句?

如何实现MySQL中删除触发器的语句?在MySQL数据库中,触发器(Trigger)是一种与表相关联的特殊类型的存储过程,它能在表发生特定的操作时被自动触发执行。MySQL提供了创建和删除触发器的语法,通过删除已存在的触发器,我们可以灵活地
如何实现MySQL中删除触发器的语句?
2023-11-08

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录