gpt4 book ai didi

我在大厂做CR——为什么建议使用枚举来替换布尔值

转载 作者:撒哈拉 更新时间:2024-10-16 02:18:59 59 4
gpt4 key购买 nike

使用枚举替换布尔值主要基于以下几个原因 ● 可读性 ● 可拓展性 ● 安全防控 。

可读性

我们会定义 boolean 类型(true 或 false)作为方法参数,虽然比较简洁,但有时候参数的含义往往不够清晰,造成阅读上的障碍, 。

比如:参数可能表示“是否开启某个功能”,但仅凭 true 和 false 并不能一眼看出其真实意图:

setDisable(false):到底是禁用还是启用 --! setInvalid(false):到底是无效还是有效 --! 。

相信我,这种“绕弯”的“双重否定”表达方式,一定会耗费你不多的脑细胞一会儿:) 当然你可能会说:“不使用否定的名词”,换成“直接表达”,setEnable(true),这一眼能识别是启用,非常直观; 是的,没错,但在我 10 余年的编程生涯里,相信我 setDisable(false) 遇到过无数次; 再举个例子: 下面代码你能“一眼知道”参数 true 代表什么含义吗?

public static void main(String[] args) {
    convert("12.3456", 2, true);
}

/**
 * 将字符串转换成指定小数位数的值
 *
 * @param value
 * @param scale
 * @param enableHalfUp 是否需要四舍五入
 * @return
 */
public static String convertToValue(String value, int scale, boolean enableHalfUp) {
    if (enableHalfUp){
        //将字符串"四舍五入"换成指定小数位数的值
    }else{
        //将字符串"截断"换到指定小数位数的值
    }
}

当然,现在 IDE 都有比较好的提示,但从“可读性”角度,是不是只能进入到方法定义看注释去了解,甚至没有注释还得去翻代码去研究这个 boolean 到底是啥语义,参数再爆炸下,你能知道每个 boolean 类型参数代表什么吗?

convert("12.3456", 2, true,false,true,false,true);

这里额外扩展一句,木宛哥搞过一段时间的 iOS 开发,如果是 Objective-C 语言,方法命名采用了较为直观的格式,可以包含多个参数名称“线性叙事”,以提高可读性。这种情况,boolean 变量前往往有“名词修饰”,会容易理解,如下所示: [NSString stringWithCString:"something" enableASCIIStringEncoding:true] 。

再从 OC 语言回过来,对于这个问题,让看看 JDK 是怎么设计的 。

public static void main(String[] args) {
    BigDecimal value = new BigDecimal("12.34567");
    //四舍五入到两位小数
    BigDecimal roundedValue = value.setScale(2, RoundingMode.HALF_UP);
    System.out.println(roundedValue);
}

看到了没,BigDecimal 的 setScale 方法,通过定义枚举:RoundingMode 代表转换规则,看到:RoundingMode.HALF_UP 一眼就知道要四舍五入,根本不需要看代码。 这样增加了可读性的,同时定义了枚举也支持更多扩展,如下马上引入第二点好处:可扩展; 。

可扩展性

如果未来需要增加更多状态,使用 boolean 会受到扩展的限制 。

例如,如果当前有两个状态:enable(开)和 disable(关),而将来需要添加待机状态,使用 boolean 就显得不够灵活。枚举则很容易扩展,能够清晰地表示更多的状态。 使用 boolean 表达功能状态:

public void configureFeature(boolean enable) {
    if (enable) {
        // 开启功能
    } else {
        // 关闭功能
    }
}

使用枚举表达功能状态:

public enum FeatureMode {
    ENABLED,
    DISABLED,
    MAINTENANCE
}

public void configureFeature(FeatureMode mode) {
    switch (mode) {
        case ENABLED:
            // 开启功能
            break;
        case DISABLED:
            // 关闭功能
            break;
        case MAINTENANCE:
            // 维护状态
            break;
        default:
            throw new IllegalArgumentException("Unknown mode: " + mode);
    }
}

类型安全

错误的使用 Boolean 包装类,有可能会引发空指针异常; 。

先抛一个问题:包装类 Boolean 有几种“值”? Boolean 是包含两个值的枚举:Boolean.TRUE 和 Boolean.FALSE;但别忘了,还可以是 null; 。

一个真实的线上故障,Boolean 在某些情况下被错误地使用,可能会造成空指针异常; 例假设你正在修改一个老旧系统的某个方法,这个方法返回 Boolean,有几千行代码:

public static void main(String[] args) {
    if (checkIfMatched("Dummy")){
        System.out.println("matched");
    }
}

/**
 * 老旧系统里一个异常复杂的方法,有几千行
 * @param str
 * @return
 */
public static Boolean checkIfMatched(String str) {
    Boolean matched;
    //假设此处存在:复杂处理逻辑,暂时用dummy代替
    if ("Dummy".equals(str)) {
        matched = true;
    } else {
        matched = false;
    }
    return matched;
}

目前没问题,但当功能不断迭代后,复杂度也陡然上升,在某个特别的分支里,没有对 Boolean 赋值,至少在编译时是不会报错的:

public static void main(String[] args) {
    if (checkIfMatched("Dummy")) {
        System.out.println("matched");
    }
}

/**
   * 老旧系统里一个异常复杂的方法,有几千行
   *
   * @param str
   * @return
   */
public static Boolean checkIfMatched(String str) {
Boolean matched = null;
//假设此处存在:复杂处理逻辑,暂时用 dummy 代替
if ("Dummy".equals(str)) {
    //模拟:代码在演进的时候,有可能存在 matched 未赋值情况
    if (false) {
        matched = true;
    }
} else {
    matched = false;
}
return matched;
}

这个时候,危险悄然而至,还记得上面的问题吗: 包装类 Boolean 有几种“值”? 现在 checkIfMatched() 方法在不同的情况下,方法会返回三个不同的值:true/false/null 这里 null 是非常危险的,如果上游使用如下方式判断条件,考虑下是否有问题?

if (checkIfMatched("Dummy")) {
    System.out.println("matched");
}

首先这里不会编译错误,但此处 if 条件处会自动拆箱,对于 null 值会得到 NullPointerException 异常; 。

小小总结

再回过头看:“哪些场景建议使用枚举来替换布尔值”,我认为要看功能点的易变程度去综合评估:“越容易变化,越不能让复杂度发散,越要由一处收敛,试想下一个 Boolean 的方法的变动是不是要评估所有上游的业务”; 所以并不是完全推翻布尔值,木宛哥在此也只是抛出一些代码的优化手段仅供参考.

最后此篇关于我在大厂做CR——为什么建议使用枚举来替换布尔值的文章就讲到这里了,如果你想了解更多关于我在大厂做CR——为什么建议使用枚举来替换布尔值的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

59 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com