2个菜鸟Java常量和枚举陷阱

在对Java和Groovy代码进行的各种代码审查中,我经常看到魔术数字和其他随机字符串在整个代码库中乱七八糟。

例如,魔术数字是下面的代码(Groovy)中的4.2:

if (swashbuckle >= 4.2) {
  ...
}

4.2是什么意思?

我的建议是将一个数字提取为一个常数,并为其赋予一个有意义的意图显示名称,以便我们所有人都可以继续理解我们的代码。

每次平台特定的常量

重构成

if (swashbuckle >= MAX_ALLOWED_CAPACITY) {
  ...
}

即使是初学者,也可以理解The Constant的值,并开始将各地的值提取为常量。 当我谈论枚举时,编写可读代码甚至更有可能,但是经验不足的开发人员很快就会陷入以下陷阱。

陷阱#1全球Über-Constants文件

应尽可能避免使用全局常量文件,例如

class Constants {
  private static final String PEACH_FLAME = "PFL"
  private static final int MAX_TOOGIT = 17
  private static final int MIN_TOOGIT = 8
  private static final String USER_NAME_AGE_PROPERTY =  "age"
  private static final String USER_NAME_FLOPPY_PROPERTY =  "floppy"
  private static final int CUSTOM_HYSLERIA_DONE = -99
  private static final List<String> WOBBA_RANGE = ['BZ, 'FLL', 'BZZ']
  // dozens of other constants...

引用StackOverflow总结得很好

我强烈建议不要使用单个常量类。 当时这似乎是个好主意,但是当开发人员拒绝记录常量并且该类增长到包含多达500个完全不相关的常量(与应用程序的完全不同的方面)时,这通常会变成完全不可读的常量文件。 代替:

  • 如果可以访问Java 5+,请使用枚举为应用程序区域定义特定的常量。 对于这些常量,应用程序区域的所有部分都应引用枚举,而不是常量。 您可以声明类似于声明类的枚举。 枚举也许是Java 5+的最(也是唯一的)有用的功能。
  • 如果您的常量仅对特定类或其子类之一有效,则将其声明为protected或public,然后将其放在层次结构中的顶级类上。 这样,子类可以访问这些常量值(如果其他类通过public访问它们,则这些常量不仅仅对特定的类有效……这意味着使用该常量的外部类可能与包含该常量的类紧密耦合。常数)
  • 如果您有一个定义了行为的接口,但是返回值或参数值应该特别,那么在该接口上定义常量是完全可以接受的,以便其他实现者可以访问它们。 但是,请避免创建仅用于保存常量的接口:它可能与仅为保存常量而创建的类一样糟糕。

一个类(例如上面的Constants示例)很快就变成了一切 。 新秀开发人员认为他通过将魔术数字和魔术字符串提取为常量来遵循良好的(代码审查)建议,但是团队很快就承担了新的维护负担。

如果你发现自己(或你的团队)这样做,请把负责任的车主如用户相关的常数常量UserService在和wobba相关常量WobbaConverter -不管它是什么

还请阅读上面评论中有关枚举的部分,因为常量并不是镇上唯一的孩子。 有时我的建议是……

首选枚举

如果您的常量可以很好地建模为枚举,请考虑枚举结构。 枚举比普通常量更通用 ; 它们是类,可以包含属性和方法。

在负责任的父类中。

更喜欢

class Person {
 enum Gender { M, F }

 String name
 Gender gender
}

过度

class Person {
 static final String GENDER_MALE = 'M'
 static final String GENDER_FEMALE = 'F'
 String name
 String gender
}

或作为使用它的班级附近的一个单独的班级 (如果它变大了)。 带有功能名称的enum类的一个很好的例子是例如一些相关的(技术)数据

/**
 * Represents medicine domain codes.
 */
public enum MedicineCode {

 /** Diagnosis e.g. "Muscle damage". */
 DIAGNOSIS("X357"),

 /** Units in medicinal context e.g. "cc/ml". */
 MEDICINE_UNIT("X523"),

 /**
 * Cause codes for diagnosis = 'Masitis' e.g. "E.coli (ECO)".
 */
 CAUSE_CODE("X536"),

 /** TreatmentType e.g. "Antibiotics". */
 INTERVAL_TYPE("X520"),
MedicineCode(String code) {
  this.code = code;
 }

 private final String code;

 public String code() {
  return code;
 }

 /**
  * Find a {@link MedicineCode} by given String code.
  *
  * @param code The code e.g. "X261"
  * @return found medicine code, or null
 */
 public static MedicineCode findByCode(String code) {
  values().find { it.code() == code }
 }

 @Override
 public String toString() {
  return name() + "(" + code() + ")"
 }
}

每当需要表示一组固定的常量时,都应使用枚举类型。 因此,新秀开发人员认为他通过遵循一些很好的(代码审查)建议,将内容提取到枚举中,封装了技术数据,使用功能名称等,但通常会陷入

陷阱#2定义枚举,并非真正正确地使用它们

因此,如果您最初具有以下方法和调用:

Medicine findMedicineForDomainCode(String code)

// which you call like: 
String intervalTypeCode = "X520"
findMedicineForDomainCode(intervalTypeCode)

并且您可能会引入像MedicineCode这样的枚举(请参见上文),将所有这些特定于域的技术代码(例如数据库“ X…”)(例如“ X520”)封装在一起,然后不要这样做:

Medicine findMedicineForDomainCode(String domainCode)

// which one keeps calling like:
String intervalTypeCode = MedicineCode.findByCode("X520")
findMedicineForDomainCode(intervalTypeCode)

我见过像这样的团队。 是的,有一个带有值的枚举类型,但是团队在整个代码中并不十分了解如何处理它们。

枚举

第一步是直接引用枚举 。 某些菜鸟开发人员通常最初已经理解了这一点,这取决于他们是否遵循Oracle Java Enum Types教程或类似内容,但是通常会导致如下所示:

Medicine findMedicineForDomainCode(String code)

// which one calls like:
String intervalTypeCode = INTERVAL_TYPE.code()
// WRONG! still using Strings here
findMedicineForDomainCode(intervalTypeCode)

有了枚举意味着我们现在可以键入所有内容,包括返回类型和方法参数

只是将枚举用作容纳字符串的容器并不是我们这样做的原因:为了获得更好的类型安全性和可读性,您应该重构代码中的所有内容,以便将域代码用作MedicineCode枚举的字符串类。

更好:

// first refactor method parameter from String to MedicineCode
Medicine findMedicineForDomainCode(MedicineCode code)

// now just pass an enum value
findMedicineForDomainCode(INTERVAL_TYPE)

然后,直到那时,在最后一个可能的时刻,您需要实际的封装String代码(“ X520”)–可以从枚举值中提取出它。

希望这有助于定义常量和使用枚举。 我无法涵盖使用适当设计的枚举类型可能拥有的所有其他“有效”用法和OO优势场景,但是希望本文能够防止Java新手陷入所描述的陷阱。

翻译自: https://www.javacodegeeks.com/2016/04/2-rookie-java-constants-enums-pitfalls.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值