编程实战:如何管理代码里的常量

摘要:相信很多同窗在见过千奇百怪的常量类以后都有这样的疑问——怎么管理这些常量类?

本文分享自华为云社区《编程实战:如何管理代码里的常量》,原文做者:技术火炬手。程序员

相信很多同窗在见过千奇百怪的常量类以后都有这样的疑问——怎么管理这些常量类,但同时又以为这个好像不是很重要,怎么管理都能用的样子,不就是个常量嘛,今天咱们就把这个问题打开来看看。spring

先看看前辈们是怎么作的

从事Web开发,有个绕不开的常量就是HTTP的状态码,不如以此为起点apache

org.springframework.http.HttpStatus

①使用枚举编程

public enum HttpStatus {
    CONTINUE(100, "Continue"),
    SWITCHING_PROTOCOLS(101, "Switching Protocols"),
    PROCESSING(102, "Processing"),
    CHECKPOINT(103, "Checkpoint"),
    OK(200, "OK"),
    CREATED(201, "Created"),
    ACCEPTED(202, "Accepted"),
    NON_AUTHORITATIVE_INFORMATION(203, "Non-Authoritative Information"),
    NO_CONTENT(204, "No Content"),
    ...

org.eclipse.jetty.http.HttpStatus

②类中定义常量segmentfault

public class HttpStatus {
    public static final int CONTINUE_100 = 100;
    public static final int SWITCHING_PROTOCOLS_101 = 101;
    public static final int PROCESSING_102 = 102;
    public static final int OK_200 = 200;
    public static final int CREATED_201 = 201;
    public static final int ACCEPTED_202 = 202;
    public static final int NON_AUTHORITATIVE_INFORMATION_203 = 203;
    public static final int NO_CONTENT_204 = 204;
    ...

org.apache.hc.core5.http.HttpStatus

③final类中定义常量框架

public final class HttpStatus {
    public static final int SC_INFORMATIONAL = 100;
    public static final int SC_CONTINUE = 100;
    public static final int SC_SWITCHING_PROTOCOLS = 101;
    public static final int SC_PROCESSING = 102;
    public static final int SC_EARLY_HINTS = 103;
    public static final int SC_SUCCESS = 200;
    public static final int SC_OK = 200;
    public static final int SC_CREATED = 201;
    public static final int SC_ACCEPTED = 202;
    public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203;
    public static final int SC_NO_CONTENT = 204;
    ...

以上都是在经常使用开源框架中的定义,在业务中还曾见过一种用法,是eclipse

④在接口中定义常量函数

public interface HttpStatus {
    public static final int CONTINUE_100 = 100;
    public static final int SWITCHING_PROTOCOLS_101 = 101;
    public static final int PROCESSING_102 = 102;
    public static final int OK_200 = 200;
    public static final int CREATED_201 = 201;
    public static final int ACCEPTED_202 = 202;
    public static final int NON_AUTHORITATIVE_INFORMATION_203 = 203;
    public static final int NO_CONTENT_204 = 204;
    ...

这种接口被称为常量接口,不过在《Effective Java》中的“接口只用于定义类型”这条建议中,特别批评了这种常量接口,认为“常量接口模式是对接口的不良使用”。原文叙述以下:this

The constant interface pattern is a poor use of interfaces. That a class uses some constants internally is an implementation detail. Implementing a constant interface causes this implementation detail to leak into the class’s exported API. It is of no consequence to the users of a class that the class implements a constant interface. In fact, it may even confuse them. Worse, it represents a commitment: if in a future release the class is modified so that it no longer needs to use the constants, it still must implement the interface to ensure binary compatibility. If a nonfinal class implements a constant interface, all of its subclasses will have their namespaces polluted by the constants in the interface.
常量接口模式是使用接口的糟糕方式。类内部会使用一些常量,这是实现细节。然而,实现常量接口会致使这个实现细节泄漏到类的导出 API 中。对于类的用户来讲,类实现一个常量接口没有什么价值。事实上,这甚至会让他们感到困惑。更糟糕的是,它表明了一种承诺:若是在未来的版本中修改了类,使其再也不须要使用常量,那么它仍然必须实现接口以确保二进制兼容性。若是一个非 final 类实现了一个常量接口,那么它的全部子类的命名空间都会被接口中的常量所污染。
考虑到常量类不该该被继承,使用final要比没有合适。

此外考虑到常量类应该不须要被实例化,将构造函数设置为private也是种额外的保护。spa

综上,使用枚举final常量类就是首选了,那么这二者之间又如何抉择呢?咱们仍是能从《Effective Java》获得有效的建议,第34条中就是在建议咱们用枚举替代int常量。

如何管理常量类

虽然枚举是首选,可是常量类不会消失,常量不仅是int常量,字符串常量也是平常开发中避不开的,并且有些时候咱们仍是会以为常量更为便捷。那该如何管理这些常量呢?

常量的坏味道

1. 巨幅常量类

把程序中全部用到的常量,都集中放到一个Constants类中。这样作会有一些缺点,

  1. 为了增长常量会致使这个类的修改会很频繁
  2. 依赖这个常量类的代码会不少
  3. 为了使用某一个常量,会致使引入不少无关的常量

2. 重复的常量定义

做为职场新人的时候,我常干的一件事情就是重复定义常量,由于我不知作别人是否认义过,在哪里定义过,与其要翻遍整个代码库去找这个常量,本身定义一个显得方便的多。

直到有一天我须要去修改一个常量的定义,前面欠下的债就须要还了。重复代码最大的问题就是,当你须要去修改或者维护那段重复的代码的时候,你须要去修改每一处,若是有遗漏,那就是bug了。重复常量也是如此。

管理思路

1. 定义多个功能单一的常量类

一个思路是按功能维度,去定义常量,一个常量类只跟某一功能相关。

如MySQLConstants、RedisConstants。

但这个有个很虚的概念,就是功能,一个功能可大可小,范畴能够是某一个类,也能够是一整个模块,这里没有定论,依赖的就是程序员聪明的头脑和丰富的经验了。

2. 不单独定义常量类

另一种思路就是不单独设计常量类,常量在哪一个类里面使用,就把常量定义到这个类中。

好比在RedisClient和RedisConfig中都用到了以前RedisConstants中的常量,能够将其分别定义在RedisClient和RedisConfig中。

但这样作有个明显的问题就是,若是多个类用到了同一个常量,若是各自定义就形成了重复,若是定义一份声明为public,就会形成两个类之间的依赖。这样来看,在没有复用诉求的状况下,就地定义才比较可取。

3. 按层次复用

上述两种方式都没有完整的解决咱们的疑惑,考虑将上述两种方式结合起来,能够获得一种按层次定义复用的方式。

  1. 跨应用复用常量:放置在二方库中,一般是client.jar中的constant目录下。
  2. 应用内复用常量:放置在一方库中,一般是common中的constant目录下。
  3. 模块内部复用常量:即在当前子工程的constant目录下。
  4. 包内复用常量:即在当前包下单独的constant目录下。
  5. 类内复用常量:直接在类内部private static final定义。

点击关注,第一时间了解华为云新鲜技术~

相关文章
相关标签/搜索