两种参数类型_布尔参数这些缺点不能忍?不如试试枚举吧

7360872343f54977ce93a503a082943f.png
全文共2222字,预计学习时长9分钟

5583e16eb7ca03c997ed32f4ad8b01ad.png
图源:unsplash

在代码库中使用布尔标志值来管理状态机似乎听起来是个不错的办法,但事实并非如此。布尔值恐怕是很多程序员接触到的第一种数据类型,它非常简单,只有两种状态: true 和false.

随着代码的发展,它很容易产生代码复杂性、可读性和可伸缩性等方面的问题。

通常,标记参数会划分函数的逻辑,迫使该函数根据值执行多项操作,这可能会导致业务逻辑中的混乱运行,代码库很容易会以下列树状结构结束运行:

1fea83440e4841358d9edb0953da62fe.png

30c32adc240e364d1a007e2979a9d366.png

背景故事

下面这个故事把布尔参数在状态机和函数参数中的弱点体现得淋漓尽致。

一群软件开发人员曾经建立了一个管理用户状态的模块,其中一名开发者坚持使用布尔值,因为该模块要求只有两个状态:ONLINE 和 OFFLINE,看起来又快又简单,直截了当。尽管大多数人并不完全同意该建议,但还是继续做了下去。

最终,类似于下面这样的函数开始占据代码库:

func setUserState(isUserOnline :Bool)

不久后,团队里来了一位新成员,他想知道下面语句的真正含义:

setUserState(true) //The new guyjust kept staring at this.

虽然有人提出了一个看起来更好的函数名(setUserOnline),但当一旦出现新的业务需求(包括另一个用户状态:BLOCKED),事情就变成了一场噩梦。来看看这些开发人员都采取了哪些办法来解决这个问题。

30c32adc240e364d1a007e2979a9d366.png

三态布尔问题

布尔值通常表示两种状态,但在某些语言中(如Java使用的是Boolean对象),可以用null来分配第三种状态。在上下文中,BLOCKED 会被设置为null。

e362a535e18a67c5ab924bbaae40b388.png
图源:unsplash

虽然这似乎不需要额外布尔值就可以适应新的用户状态,但会很容易得到NullPointerExceptions结果。

另外,在不同情况下,要想区分false和null会比较棘手。比如,布尔属性game.isPlaying为true时则清楚地表明游戏处于播放模式。但为false或null时,false表示游戏暂停或停止。

如你所见,false没有提供足够信息来轻松识别和回忆其绑定状态,三态布尔值只会使逻辑复杂化。

此外,当系统要求包含另一个称为EXPIRED的状态,会出现什么情况?由于现在有四个状态,这种方法无法解决了。接着来看看大多数开发人员采用的另一种方法。

30c32adc240e364d1a007e2979a9d366.png

多个布尔值带来隐藏的依赖项

开发人员最终扩展了前一个函数的签名,为新状态添加了两个布尔参数:

func setUserState(
isUserOnline : Bool,
isUserBlocked : Bool,
isUserExpired : Bool)

看起来像是满足业务需求的简单扩展,却被迫在代码库中引入了隐藏依赖项和大量新组合。

创建的两个隐藏依赖项是isUserOnline — isUserExpired和 isUserOnline — isUserBlocked。现在需要明确管理额外状态,以避免冲突状态。例如,被拦截/过期的用户不能在线。以下是要处理的两种冲突状态的示例:

#Condition 1: isUserOnline:false and isUserExpired: true
#Condition 2: isUserOnline: false and isUserBlocked: true

添加状态越多,函数很容易就能变成一长串参数。事情变得不可持续,因为最终会遇到很多&&,||,和其他复杂的分支逻辑来处理互斥和相关的布尔值。

30c32adc240e364d1a007e2979a9d366.png

布尔值具有类型安全性和可读性问题

使用多个布尔值,很有可能将它们混淆,最终还可能会传递错误值(可能来自其他对象),且编译器甚至不会作出反应。在重构和执行代码审查时,这可能是一场噩梦,需要编写大量的单元测试来解决此类问题。

494784e5bd2bd8d8856716b82e532815.png
图源:unsplash

此外,很容易忘记布尔变量的false或true值的真正含义,理解充满布尔值的函数调用(如下所示)只会变得非常困难:

setUserState(true, false, false)

有人可能会说,现在很多编程语言都支持可以提高函数可读性的命名参数。但话又说回来,可能会意外传递一个反向或不正确的布尔值,但函数签名仍然匹配。

如果用枚举而不是布尔值,这个故事中的软件开发人员就能避免这些麻烦。

30c32adc240e364d1a007e2979a9d366.png

选用枚举,避免用布尔值

枚举数是一种数据类型,由一组能够以类型安全方式使用的命名值组成。虽然它看起来可能不像布尔值那么简单,但用枚举或其他用户定义类型有助于避免设置具有多个分支的复杂if语句。

enum UserStates{case active
case inactive
case blocked
case expired}

1. 枚举清晰明了

枚举强制命名所有状态,这让人很容易理解它们的含义——从而创建自文档化代码。同样,枚举清楚地表明这些值互相排斥,从而消除冲突状态的疑问。

将枚举作为函数中的参数传递更加清晰,有助于避免神秘的布尔值。只需比较下面两行:

setUserState(true,false, false)//The version below is more concise andclearer.setUserState(UserStates.active)

2. 枚举具有类型安全性

对于枚举,不能给它分配除指定值以外的任何值,因为其具有类型安全性,这样就不可能出现意外交换值或传递无效状态,因为能够被编译器发现。

并非所有语言都支持本机枚举,在此种情况下,可以创建自定义类型。例如,在JavaScript中,可以通过“冻结”对象中的常量来解决此问题:

constUserState= {ACTIVE: 1,INACTIVE: 2,BLOCKED: 3,EXPIRED: 4};Object.freeze(UserState);

3.枚举使扩展和重构更加容易

在枚举数中扩展值的集合更容易,因为与布尔值不同,可能状态组合的数量不会在每种新情况下加倍。

而且,许多编译器很智能,足以指示需要进行哪些更改才能适应新枚举。比如,Swift会引发错误,同时,使用其他语言,可以轻松查明枚举中出现的所有案例。

用额外的新案例扩展已经存在的枚举不费吹灰之力,因为数据类型保持不变,这使得重构整体变得更加容易。

d7c49946384504867016f238c76df1b0.png
图源:unsplash

当然,布尔值也不是一无是处。如果确定状态是二进制,且互斥,或方法名称已经描述了状态(例如setEnabled(true)),那么就放心大胆地用布尔值吧。

但通常情况下,需求会发生变化,也需要添加新状态。因此包含两个元素的枚举值得一试,它比布尔标志更安全。枚举有助于将来验证代码,且无需跟踪布尔字段。

别贪图省事儿滥用布尔值,枚举是一个不错的选择。

9ce83cb5e6f9d09eabf9f3fb5868cf15.png

留言点赞关注

我们一起分享AI学习与发展的干货

编译组:齐鑫濛、刘露敏

相关链接:https://medium.com/better-programming/dont-use-boolean-arguments-use-enums-c7cd7ab1876a

如转载,请私信小芯,遵守转载规范

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

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

相关文章

405 not allowed怎么解决_英语口语:“您拨叫的用户不在服务区”这类电话常用语怎么说...

1、空号:中文:您好!您所拨打的号码是空号,请核对后再拨。英文:Sorry! The number you dialed does not exist, please check it and dial later.2、被叫用户关机:中文:您好!您所拨打…

利用代码分别实现jdk动态代理和cglib动态代理_代理模式实现方式及优缺点对比...

作者:爱宝贝丶来源:https://my.oschina.net/zhangxufeng/blog/1633187代理模式最典型的应用就是AOP,本文结合主要讲解了代理模式的几种实现方式:静态代理和动态代理,这里动态代理又可以分为jdk代理和Cglib代理&#xf…

防抖 节流_防抖节流与前端性能优化

在我们日常的开发中经常会用到一些容易被反复触发的事件。比如:scroll、resize、鼠标事件(mousemove,mouseover等)、键盘事件(keyup、keydown)。频繁触发回调导致的大量计算会引发页面的抖动甚至卡顿。为了规避这种情况,我们需要一些手段来控制事件被触发…

惠普10代的服务器有哪些型号,英特尔官方科普:秒懂十代酷睿型号怎么认!

今日,英特尔官方微博再次放出科普:十代酷睿处理器是如何命名的?英特尔介绍,以酷睿i7-1065G7为例,“i7”为产品型号,“1065”中的“10”代表十代酷睿,“65”为CPU代号,“G7”为显卡性…

form提交后台注解拿不到数据_浏览器是如何将用户数据发送到服务器的?

今天是刘小爱学习Java的第89天。感谢你的观看,谢谢你。话不多说,开始今天的学习:在学习之前,先思考如下问题:对于浏览器来说:如何将用户数据发送到服务器呢?数据传输的格式是怎么样的呢&#xf…

proxmoxve打造云桌面_微软云电脑Cloud PC曝光:配置一般还不便宜

光纤宽带的普及和提速、5G的兴起,让云电脑、云游戏、云手机等产品和应用红火起来。而微软也正在开发一款名为Cloud PC的云端Windows操作系统,并计划2021年正式推出。据报道,Cloud PC是由Azure云服务支撑,基于虚拟桌面打造的&#…

alpine linux图形界面_跟光磊学Linux运维-Linux入门与基本使用

认识Linux用户在安装CentOS8.2时,设置过root用户的密码,同时也创建了用户guanglei。其中root用户是系统自带的管理员账户,也被称为超级用户,root用户接近系统完整的控制能力,对系统损害几乎有无限的能力。运维人员在生…

休眠 嵌入式_内幕消息:嵌入式软件挤出最低功耗模式

低功耗运行仍然是各行业应用的关键驱动因素。随着睡眠模式的增加,电源管理突然从单纯的硬件问题转移到软件开发人员必须考虑的事情上。功耗模式的最简单应用是当系统空闲时,将其置于休眠状态。然而,今天的MCU提供多种低功耗模式,进…

cnn 验证集 参与训练吗_一个简单的零基础的机器学习教程之二,字母数字验证码识别...

一.前言基于前面我发的贴子 土味程序员:一个简单的零基础的机器学习教程,Pytorch搭建Faster R-CNN目标检测平台​zhuanlan.zhihu.com一个非常震撼的目标检测的例子。上个帖子从环境安装到调试代码再到图片检测视频检测一个详细的教程,今天我来…

activiti 文档_免费、开源、多平台的PDF文档处理软件——PDFsam Basic

今天给大家推荐的是一款免费、开源、多平台支持的PDF文档处理软件——PDFsam BasicPDFsam Basic是为普通用户提供的免费开源解决方案,提供了PDF文档拆分、合并、混合、提取页面和旋转等等功能。01. 文档分割PDFsam Basic可以通过给定页码、书签级别,把PD…

@data注解不生效_你说啥什么?注解你还不会?

点击蓝色字免费订阅,每天收到这样的好信息前言:最近有不少粉丝关注本公众号。并且我已经成功开通了流量主同时会赚一点点广告费,我打算每个月把这部分钱拿出来给大家买点书刊,算是给大家一点福利吧。大家想买什么书扫描下方的加他拉你加群。最后,非常感谢大家的关注…

yearning 2. 部署_对于企业来说,在选择协同办公系统的时候,选择私有化部署的数据安全一些,还是使用云服务器比较安全?...

当然是私有化部署!因为它除了安全,还有个性化~私有化部署,简单理解就是企业自己购买或租赁服务器,或者由服务商提供免费的云资源,然后将整个系统部署在企业自有的服务器上。采用这种方式,企业就不用担心自家…

numpy 平方_Numpy的终极备忘录

作者|Rashida Nasrin Sucky 编译|VK 来源|Towards Data Science Python是开源的。对于使用python的数据科学家来说,Numpy这个库是必不可少的。其他一些基本的库,如Pandas,Scipy是建立在Numpy的基础上。所以我决定做一份备忘录。这里我包括了到…

linux HZ 值_Linux的serial串口控制台

本人大多数情况都是在调试服务器大量的linux服务器,很多情况下也不没有必要专门准备KVM(keyboard, video, mouse),甚至有些机器根本就没有显示器接口。如何调试的?闲来无事,分享一下。有些人说“ 给我个Lin…

nginx文件系统大小_详解Nginx系列

1.Nginx特点Nginx是一个事件驱动架构,而非传统过程驱动架构。具有内存占用低,当并发连接大时,能够预测内存使用率。Nginx改变了传统的web服务器体系架构,提高了响应速度,起初Nginx开发的目标是实现10倍以上的性能&…

不可用于python编程开发的是_Python编程语言可做而不应做的一些事是什么_Python视频_Python视频教程_编程语言_课课家...

在 -5 ~ 256 之间的整型数值可以进行互换 当我在考虑这个能用在什么地方的时候,我有点迷茫了。撇开这点,你在此之前知道 Python 中的数字是可以改变其实际含义的吗?之所有会有这种情况,是因为 Python 解释器为 -5 ~ 256 之间的每一…

iphone7尺寸_iPhone 12 mini、12 Pro Max真机对比图赏:尺寸直观感受下

11月6日消息,等待多时,苹果iPhone 12 mini、iPhone 12 Pro Max将于今晚21点正式开启预定,11月13日发售。iPhone 12 mini是苹果尺寸最小、最轻薄的5G手机,而iPhone 12 Pro Max则是综合实力最强大,拍照最好的iPhone。赶在…

人脸识别错误代码437是什么意思_lol手游repeat ready check fails什么意思 解决攻略大全...

导读 lol手游repeat ready check fails什么意思?在日服内出现英文的错误代码,这两种语言的差异,会让国服玩家变得越来越混乱,想要解决问题,还是一如既往的得弄清楚代码内提示的内容是什么... lol手游repeat ready chec…

matlab求傅里叶级数展开式_连续时间的傅里叶级数

如果信号x(t)是周期信号,那么对于所有t,存在一个最小正数T,使得x(t)x(tT)其中T为这个周期信号的最小正周期。根据周期函数的周期性:x(t)x(tN*T)(N为整数)称为这个信号的基波频率周期信号x(t)也可以用周期复指数信号表示则因为x(t)是周期信号&…

delphi chart 曲线实时_发展学生曲线跑能力的体育游戏及运用研究

不想错过精彩的推送?戳左上角蓝字“体育教师大本营”关注并点击右上角●●●菜单栏选择“设置⭐️标”或“置顶公众号”每天早上7:00,体委伴您成长 一、曲线跑教材跑是人类在日常生活社会交往、生产劳动中的基本活动能力之一,从一定程度上反映…