使用enum vs Boolean?

The*_*boy 13 java postgresql hibernate

这可能最初似乎是通用的,但事实上,我实际上是在做出我需要使用的决定.

我目前正在进行的工作涉及就业申请,其中需要在某些时候标记为活动或非活动.提交申请时,默认为" 有效".出于某些原因,稍后可能会将其设置为" 非活动".它只能是其中之一,永远不会为null(如果这改变了什么).

我在Java + Hibernate + PostgresSQL中使用它,以防这也有所不同.我的第一直觉是使用布尔值作为我的解决方案,以便它真正作为一个标志,但我有同事建议使用枚举整数作为更多的状态而不是标志.

我已经使用所有上述解决方案解决了诸如此类的问题,并且它们对彼此都显得有些透明.

有没有一种方法可以更好地适应这种情况?

Col*_*inD 13

即使忽略了将来添加更多状态类型的可能性(这当然是一个很好的论据enum),我认为enum绝对是正确的方法.您没有建模布尔条件,您正在建模应用程序的状态.想一想:应用程序的状态不是,它是活动的还是非活动的!状态enum将以最自然的方式表示.

使用枚举还可以获得许多内置优势,例如将每个状态的文本描述直接绑定到它,因此您不必执行类似的操作

String text = application.isActive() ? "Active" : "Inactive";
Run Code Online (Sandbox Code Playgroud)

你可以这样做

String text = application.getStatus().toString();
Run Code Online (Sandbox Code Playgroud)

此外,您可以使用每个枚举实现不同的抽象方法将特定行为直接绑定到每个状态,将特定数据与每个状态相关联等.

您也可以轻松地允许isActive基于状态的布尔检查...如果您只是存储一个,则不能轻易地做到这一点boolean.

public boolean isActive() {
  return status == Status.ACTIVE;
}
Run Code Online (Sandbox Code Playgroud)

并且null不应该是有效状态的事实是无关紧要的......只要确保存储状态(例如,您的EmploymentApplication类或其他)的NullPointerException任何类都抛出一个,如果有人试图null在其上设置状态.


Kar*_*tel 11

绝对不要使用int.使用枚举是面向未来的; 你必须自己决定哪些更具可读性,以及YAGNI是否适用.要知道这boolean不是一回事Boolean; Boolean是一个类名,因此,类型的变量Boolean可以为null; 而是boolean原始的.


Buh*_*ndi 10

这完全取决于您的要求/规格.如果您只想将状态记录为活动或非活动状态,最好的方法是使用boolean.

但如果在将来,您将拥有如下状态:

  • 活性
  • INACTIVE
  • BLOCKED

Enums非常适合您.在你的情况下,现在,布尔值就足够了.不要过早地尝试过度复杂化,否则您将失去对系统设计和开发的关注.

  • 我强烈反对使用枚举是"过度复杂"的事情.枚举是"主动"和"不活动"比"真实"和"假"更自然的表示,并且具有许多优点,允许与这些状态相关的代码(包括仅为每个状态获取名称)集中与他们的定义而不是分散在代码的其他地方. (17认同)
  • @ColinD,我建议的是,如果一个状态基本上是活动/非活动的,一个简单的`private boolean active`就足够了.在OP知道状态的确切规范之前,不必创建您不知道的值的枚举.此外,在PostGres中表示布尔字段比在系统中添加附加值时更改表字段添加新值更简单.目前,OP应该从提供的内容开始. (4认同)
  • 使用多个布尔字段(例如`active`,`suspended`和`blocked`)的优点是,将来添加新状态不会影响现有代码和查询,并且这些条件表达式通常会更简单.也就是说,一个条件可能是`active == false`,而不是关心为什么它恰好处于非活动状态(暂停或阻塞或其他一些未来状态)......当然,缺点是更多字段和更多数据需要维护 - 以及无效/冲突状态的风险,例如`active = false`和`suspended = true`同时,您的设计/代码需要防止这种风险. (2认同)

Bas*_*que 6

布尔值在商业和工业中很少见

根据我为企业构建自定义应用程序的经验,诸如“女性/男性”或“开/关”之类的明显二元性几乎总是会演变或演变为多个值。

  • “女/男”变为“未知/女/男”
  • “开/关”变成“开/预热/冷却/关闭”
  • “未完成/已完成”变为“未完成/处理中/已完成”

业务规则通常在早期并不完全了解,或者随着时间的推移而变化。

像我的许多同事一样,我学会了从不将此类值定义为布尔值的艰难方法。稍后从布尔值更改为多个值非常昂贵且有风险。

Java 枚举

枚举比布尔值还有其他好处。

Java 枚举灵活而强大

EnumJava 中的工具比大多数其他语言中的枚举更加灵活、强大和有用。请参阅Oracle 教程

在您的枚举定义中,您可以容纳值的表示形式,以便向用户展示和存储在数据库或文件中。这为程序员提供了一个方便的一站式商店,可以阅读有关此枚举的所有信息以及它在您的应用程序中的使用方式。

这是一个完整的例子。这一类显示了我们在用户界面中使用的值以及我们保留的值。

package com.basilbourque.example;

public enum Status {
    ACTIVE( "Active" , "active" ),
    INACTIVE( "Inactive" , "inactive" ),
    UNKNOWN( "Unknown" , "unknown" );

    private String displayName, codeName;

    Status ( String displayName , String codeName ) {
        this.displayName = displayName;
        this.codeName = codeName;
    }

    public String getDisplayName () { return this.displayName; }  // Or even add a `Locale` argument to support localization.

    public String getCodeName () { return this.codeName; }

    // To find a `Status` enum object matching input retrieved from a database.
    static public Status ofCodeName ( String codeName ) {
        // Loop each of the enum objects to find a match.
        for ( Status s : Status.values() ) {
            if ( s.getCodeName().equals( codeName ) ) { return s; }
        }
        throw new IllegalArgumentException( "No such Status code name as: " + codeName );
    }

    @Override
    public String toString() { return "app-status-" + this.getCodeName() ; }

}
Run Code Online (Sandbox Code Playgroud)

将持久值转换回枚举对象

请注意可以返回Status与从数据库中检索到的持久值匹配的对象的静态方法:

Status s = Status.ofCodeName( myResultSet.getString( "code" ) ) ;
Run Code Online (Sandbox Code Playgroud)

灵活的集合/地图

在 Java 中,枚举有自己的实现,Set并且Map在使用的内存非常少和执行速度非常快方面都进行了高度优化。

Set< Status > auditApprovedStatuses = EnumSet.of( Status.ACTIVE , Status.INACTIVE ) ;  
Set< Status > auditAlertStatuses = EnumSet.of( Status.UNKNOWN ) ;

…

if( auditAlertStatuses.contains( application.getStatus() ) ) {
    this.alertAuditor( application ) ;
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果您对应用程序状态的定义发生变化,更新这些集合定义是多么容易。

信息toString价值

虽然布尔值显示为字符串truefalse字符串,但在您的枚举中,您可以覆盖toString以生成信息量更大的值,例如app-status-inactive.

这些值在记录、跟踪或调试时可能非常有用。


Art*_*are 5

两者都不能做吗?

enum Status {
    ACTIVE(true), INACTIVE(false);
    private final boolean value;
    Status(boolean value) {
        this.value = value;
    }
    boolean getValue() {
        return this.value;
    }
}
Run Code Online (Sandbox Code Playgroud)

这难道不是让你两全其美吗?它允许您使用名称为 ACTIVE 和 INACTIVE 的布尔值,而不是 true 和 false?