网站建设论文百度云盘,专业的东莞网站推广,免费ip代理服务器,大公司网站搭建公司全文共2222字#xff0c;预计学习时长9分钟图源#xff1a;unsplash在代码库中使用布尔标志值来管理状态机似乎听起来是个不错的办法#xff0c;但事实并非如此。布尔值恐怕是很多程序员接触到的第一种数据类型#xff0c;它非常简单#xff0c;只有两种状态: true 和fals…全文共2222字预计学习时长9分钟图源unsplash在代码库中使用布尔标志值来管理状态机似乎听起来是个不错的办法但事实并非如此。布尔值恐怕是很多程序员接触到的第一种数据类型它非常简单只有两种状态: true 和false.随着代码的发展它很容易产生代码复杂性、可读性和可伸缩性等方面的问题。通常标记参数会划分函数的逻辑迫使该函数根据值执行多项操作这可能会导致业务逻辑中的混乱运行代码库很容易会以下列树状结构结束运行背景故事下面这个故事把布尔参数在状态机和函数参数中的弱点体现得淋漓尽致。一群软件开发人员曾经建立了一个管理用户状态的模块其中一名开发者坚持使用布尔值因为该模块要求只有两个状态ONLINE 和 OFFLINE看起来又快又简单直截了当。尽管大多数人并不完全同意该建议但还是继续做了下去。最终类似于下面这样的函数开始占据代码库func setUserState(isUserOnline :Bool)不久后团队里来了一位新成员他想知道下面语句的真正含义setUserState(true) //The new guyjust kept staring at this.虽然有人提出了一个看起来更好的函数名(setUserOnline)但当一旦出现新的业务需求包括另一个用户状态BLOCKED事情就变成了一场噩梦。来看看这些开发人员都采取了哪些办法来解决这个问题。三态布尔问题布尔值通常表示两种状态但在某些语言中(如Java使用的是Boolean对象)可以用null来分配第三种状态。在上下文中BLOCKED 会被设置为null。图源unsplash虽然这似乎不需要额外布尔值就可以适应新的用户状态但会很容易得到NullPointerExceptions结果。另外在不同情况下要想区分false和null会比较棘手。比如布尔属性game.isPlaying为true时则清楚地表明游戏处于播放模式。但为false或null时false表示游戏暂停或停止。如你所见false没有提供足够信息来轻松识别和回忆其绑定状态三态布尔值只会使逻辑复杂化。此外当系统要求包含另一个称为EXPIRED的状态会出现什么情况由于现在有四个状态这种方法无法解决了。接着来看看大多数开发人员采用的另一种方法。多个布尔值带来隐藏的依赖项开发人员最终扩展了前一个函数的签名为新状态添加了两个布尔参数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添加状态越多函数很容易就能变成一长串参数。事情变得不可持续因为最终会遇到很多,||和其他复杂的分支逻辑来处理互斥和相关的布尔值。布尔值具有类型安全性和可读性问题使用多个布尔值很有可能将它们混淆最终还可能会传递错误值可能来自其他对象且编译器甚至不会作出反应。在重构和执行代码审查时这可能是一场噩梦需要编写大量的单元测试来解决此类问题。图源unsplash此外很容易忘记布尔变量的false或true值的真正含义理解充满布尔值的函数调用(如下所示)只会变得非常困难setUserState(true, false, false)有人可能会说现在很多编程语言都支持可以提高函数可读性的命名参数。但话又说回来可能会意外传递一个反向或不正确的布尔值但函数签名仍然匹配。如果用枚举而不是布尔值这个故事中的软件开发人员就能避免这些麻烦。选用枚举避免用布尔值枚举数是一种数据类型由一组能够以类型安全方式使用的命名值组成。虽然它看起来可能不像布尔值那么简单但用枚举或其他用户定义类型有助于避免设置具有多个分支的复杂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会引发错误同时使用其他语言可以轻松查明枚举中出现的所有案例。用额外的新案例扩展已经存在的枚举不费吹灰之力因为数据类型保持不变这使得重构整体变得更加容易。图源unsplash当然布尔值也不是一无是处。如果确定状态是二进制且互斥或方法名称已经描述了状态例如setEnabled(true)那么就放心大胆地用布尔值吧。但通常情况下需求会发生变化也需要添加新状态。因此包含两个元素的枚举值得一试它比布尔标志更安全。枚举有助于将来验证代码且无需跟踪布尔字段。别贪图省事儿滥用布尔值枚举是一个不错的选择。留言点赞关注我们一起分享AI学习与发展的干货编译组齐鑫濛、刘露敏相关链接https://medium.com/better-programming/dont-use-boolean-arguments-use-enums-c7cd7ab1876a如转载请私信小芯遵守转载规范