Java 中的常量——反模式

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 63w+ 字,讲解图 2808+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2200+ 小伙伴加入学习 ,欢迎点击围观

通常我们会在应用程序中看到常量文件的需求,它存储要在多个位置共享的常量。在设计应用程序时,我遇到了类似的情况,我们需要在应用程序的多个位置使用各种常量。

我确信,我需要一个单独的文件来存储公共静态常量。但我不太确定将其设为接口还是类。 (枚举不适合我的要求)。所以我有两个选择:

一个接口,例如


 package one;
public interface Constants {
String NAME="name1";
int MAX_VAL=25;
}

或者


 package one;
public interface Constants {
String NAME="name1";
int MAX_VAL=25;
}


我的观点是使用接口。我的论点是,由于接口自动将字段设置为 public static 和 final,这将是有利的,以防万一有人错过将它们添加到新常量。它还使代码看起来更简单、更清晰。

此外,简单测试表明相同的接口(字节类)的大小为 209 字节(在 ubuntu 14.04 上),而类(字节类)的大小为 366 字节(在相同的操作系统上)。更小的字节类意味着更少的加载和维护。此外,在加载接口时,JVM 无需担心它为类提供的额外功能(例如方法的重载/动态绑定等),因此加载速度更快。

这看起来不错,但这是反模式的典型案例。尽管使用接口作为常量可能看起来很有帮助,但它会留下一个漏洞,可能会影响以后的应用程序策略。

假设有一个类,它在很大程度上依赖于这些常量。开发人员在编写代码时看到接口名称在整个类中重复出现,例如


 package one;
public interface Constants {
String NAME="name1";
int MAX_VAL=25;
}


所以,为了 “清理” 他可能想要实现接口的代码,这样他就不需要到处写“packagename.Constants”,所有的常量都可以直接访问。

但是一旦他实现了接口,所有常量就成为他的“合同”的一部分(因为它们是公共的和静态的)。这可能会导致在类的契约中添加非必需的常量部分。这动摇了基本面,并增加了混乱。在 Java 中没有办法阻止接口被类实现。

另一方面,我们可以使类最终化,因此不可扩展。此外,我们可以将构造函数设为私有,因此此类是不可实例化的。由于新类是不可实例化的,因此它永远不会违约。此外,如果在同一个类中多次使用特定常量,开发人员可能会使用静态导入。

因此,一个好的 Constants 类设计应该是:


 package one;
public interface Constants {
String NAME="name1";
int MAX_VAL=25;
}

静态导入的一个例子是:


 package one;
public interface Constants {
String NAME="name1";
int MAX_VAL=25;
}


这样的设计问题也称为 Constant Interface Anti-pattern

相关文章