Java 开发技巧:减少魔法值的使用

举报
Aion 发表于 2022/09/18 19:41:44 2022/09/18
【摘要】 代码中有魔法值会造成代码可读性低(与代码量成正比)。还会造成维护困难,改动一个数值便要大动干戈,牵一发而动全身。应当尽力消灭或减少魔法值,提高维护效率和代码可读性。

前言

代码中有魔法值会造成代码可读性低(与代码量成正比)。还会造成维护困难,改动一个数值便要大动干戈,牵一发而动全身。应当尽力消灭或减少魔法值,提高维护效率和代码可读性。


1 魔法值

在Java开发中,Java魔法值又叫做魔法数值、魔法数字、魔法值。当我们开发或重构老代码中遇到了类似这种写法:

public void attend(String value) {
    if ("0".equals(value)) {
        // TODO
    } else if ("1".equals(value)) {
        // TODO
    } else {
        // TODO
    }
}


脑壳疼!从 Java语法上无懈可击,但是从业务上却让人无法理解其中的含义。上面看到的字符窜的 "0""1" 统称为魔法值 。


2 魔法值的处理方式

上面的代码我们往往需要通过上下文推断出来,如果是非常复杂的业务或者十年前的代码那就更惨了,搞不好文档也没有。所以我们要尽量避免出现魔法值。今天就来讲几种避免魔法值的操作。


2.1 静态常量

如果该值的作用域在一个类中或者同一个包下,一般可以使用静态常量来解决。

private static final String FEMALE = "0";
    private static final String MALE = "1";
    public void attend(String value) {
        if (FEMALE.equals(value)) {
            // TODO
        } else if (MALE.equals(value)) {
            // TODO
        } else {
            // TODO
        }
    }
}


是不是清晰了许多,原来 0 和 1 代表的是性别(当然需要配合你良好的变量命名习惯)。


2.2 使用接口

既然我们使用了静态常量那么我们可以将魔法值封装入接口也是可以的。

public interface Gender {
    String FEMALE = "0";
    String MALE = "1";
}


2.3 使用枚举

接口的意义在于提供抽象的功能而不是存储一些常量值,显然违背了接口设计的初衷。所以jdk1.5引入了枚举类型enum。很多情况这种写法就够用了,你可以通过 GenderEnum.MALE.ordinal() 获取对应枚举的数字序号,也可以通过GenderEnum.MALE.name()获取对应枚举的字符串名称。他们大多数情况下都可以用来进行一些逻辑标识。但是满足不了我们上面最初的设计,我们需要来改造一下枚举类的构造函数。

public enum GenderEnum {
    FEMALE("0"),
    MALE("1");
    private final String value;
    GenderEnum(String value) {
        this.value = value;
    }
    public String value() {
        return this.value;
    }
}


这样改写之后我们就能通过 value() 方法拿到具体的值了。

自己再增加点需求,以达到你的枚举更加友好的可读性。参考如下代码片段:

public enum GenderEnum {
    UNKNOWN("-1", "未知"),
    FEMALE("0", "女性"),
    MALE("1", "男性");
    private final String value;
    private final String description;
    GenderEnum(String value, String description) {
        this.value = value;
        this.description = description;
    }
    public String value() {
        return this.value;
    }
    public String description() {
        return this.description;
    }
}


description值不但可以帮助我们知道该枚举的实际代表意义,甚至可以作为一种说明返回给前端业务。


2.4 内部类

public class ResponseMessage {
    public static final class Status {
        public static final String SUCCESS = "SUCCESS";
        public static final String WARN = "WARN";
        public static final String ERROR = "ERROR";
        public static final String FAIL = "FAIL";
        public static final Integer ENABLE = 0;
        public static final Integer DISABLE = 1;
    }
}


通过 [类名.内部类名.属性] 访问和调用,例如:

ResponseMessage.Status.ENABLE、

ResponseMessage.Status.SUCCESS、

ResponseMessage.Status.WARN


小贴士:枚举尽量不要使用中文声明,如 FEMALE 直接声明为 「女性」。另外枚举是单例的,因此无法 clone 和反序列化。


3 总结

对于魔法值在业务逻辑上面好像没有什么太大的影响,也不是很致命的问题,他不影响我们的代码运行,也不影响我们代码的使用。但是为了遵循规范,有效避免一些不必要的问题时,提升我们的开发效率和提高可读性。用常量或者参数,有如下好处:


1)代码更容易看懂,代码逻辑更清晰

看到代码就知道意义。业务逻辑中常用数字代表特定的意义。比如1:开启,0:关闭;1:男性,0:女性。如果直接看到数字,什么鬼?我都不知道是什么。


2)代码维护和优化更容易

如果随便用魔法数字,那么如果要修改,我自己都怕,鬼知道,这个魔法参数,和其他代码上的联系。比如,一个地方的数字“1”和另一个地方的数字“1”,这连个“1”他们是亲戚吗?谁知道!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。