【问题标题】:What'd be the synthetically correct way of imitating extendable enum behavior?模仿可扩展枚举行为的综合正确方法是什么?
【发布时间】:2020-10-26 14:17:18
【问题描述】:

传统上,当我有一个枚举时:

public enum SomeEnum implements Serializable {
    TYPE_1,
    TYPE_2;
}

或一个类:

public class Country {

    public static final Country SOME_COUNTRY = new Country("someCode");

    private final String code;

    ...
}

在控制器中,我返回这些值来填充一些选择:

@RestController(...)
public List<Field> getFields() {

    return Arrays.asList(SomeEnum.class.getEnumConstants());

    // or

    return Arrays.asList(Country.class.getDeclaredFields());
}

目前,我正在开发一个可以由某些最终产品导入的 webhook 库。一些事件名称来自库本身,但其中一些不在库中(但在最终产品代码中):

Webhook 类如下所示:

public class Webhook {

    private String url;

    private List<WebhookEvent> events;

    ...
}

WebhookEvent如下:

public class WebhookEvent Serializable {

    private long id;

    private String name;

    ...
}

并且WebhookEvents 是从数据库中填充的。我不想在最终产品中创建一个持有类,例如:

public class EnabledEvent {

    public static final WebhookEvent SOME_EVENT = new WebhookEvent("event.name");

    ...
}

因为这将从 2 个不同的点控制应用程序的行为。但相反,我希望能够在数据库中有新条目时立即返回这些常量/字段。基本上我希望能够模仿基于数据库中的条目扩展常量/枚举的行为。有没有正确的方法以编程方式实现这一目标?

【问题讨论】:

  • 在一个项目中,我们有一个类似的 enums 列表,我们必须将其放入数据库并稍后获取,但有些类型的元素较少,所以我们最终使用了两种方式(至少节省了一些调用 db)。
  • 我非常想看看你在不保存调用到数据库的情况下会怎样。你能举个例子吗?在这种情况下,使用缓存几乎总是可以轻松避免 db 调用。
  • 试图在答案中总结它,让我知道以防从您的角度来看有什么需要改进的地方。

标签: java enums constants


【解决方案1】:

在我们的例子中,我们必须验证许多常量。这个常量文件开始堆积起来。因此,我们不得不设计一种不同的方式,最终只为常量创建了一个单独的表,因此您可以添加或删除/禁用一次不需要的,而无需重新编译您的代码(尽管您必须这样做,如果有依赖案例)。

例如,假设您有以下患者状态 (STATUS):

稳定、严重、死亡、恢复和不适用

以及 TEST_RESULT 的以下状态:

TEST_PENDING、TEST_NEGATIVE 和 TEST_POSITIVE

表格如下所示:

------------------------------------------------------------------------
enum_code       enum_type       enum_name       enum_desc       disabled
------------------------------------------------------------------------
001             STATUS          STABLE                          false
002             STATUS          CRITICAL                        false
003             STATUS          DECEASED                        false
004             STATUS          RECOVERED                       false
005             STATUS          NA                              false
100             TEST_RESULT     TEST_PENDING                    false
101             TEST_RESULT     TEST_NEGATIVE                   false
102             TEST_RESULT     TEST_POSITIVE                   false
------------------------------------------------------------------------
@Entity
@Table(name="constant_enum")
public class ConstantEnum implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="enum_code")
    private Integer enumCode;
    
    private boolean disabled;
    
    @Column(name="enum_desc")
    private String enumDesc;
    
    
    @Column(name="enum_name")
    private String enumName;

    @Column(name="enum_type") // this is the discriminator
    private String enumType;
    
    //getters and setters

}

【讨论】:

  • 我明白了,但问题从这里开始。这也是我目前得到的。问题是如何将它们列为常量。
  • 那么我理解错了你的问题。我希望看到其他选项弹出,这将非常有帮助
  • 仅供参考,这种表被 DBA 归类为反模式,称为 One True Lookup Table。
  • @NathanHughes 您是 DBA,还是您对这个特殊案例的看法?
  • @NathanHughes 我不打算将每个enum 保存在一个巨大的数据库表中,而是将单个枚举保存在一个表中,所以我猜这个评论不适用于我的情况。无论如何,谢谢!
【解决方案2】:

我最终删除了与数据库的连接,并在类本身中定义了静态变量,并使用静态 ofValue 方法来创建对象:

public class SomeClass implements Serializable {

    public static final SomeClass MY_CONSTANT_1 = new SomeClass("static.value");

    public static SomeClass [] values = new SomeClass []{
            SomeClass .MY_CONSTANT_1,
            ...
    };

    private String name;

    public SomeClass (String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static SomeClass ofValue(String name){
        if(StringUtils.isEmpty(name)) return null;
        for(SomeClass value : values) if(value .getName().equalsIgnoreCase(name)) return event;
        throw new IllegalArgumentException(String.format("Couldn't convert value : %s into a valid %s object", name, SomeClass.class.getName()));
    }
}

这样可以展开如下:

public class ExtendedSomeClass extends SomeClass implements Serializable {

    public static final SomeClass MY_CONSTANT_2 = new SomeClass ("static.value.2");

    public static SomeClass[] values = new SomeClass[]{
            SomeClass.MY_CONSTANT_2,
    };

    public static SomeClass ofValue(String name){
        if(StringUtils.isEmpty(name)) return null;
        for(SomeClass event : values) if(event.getName().equalsIgnoreCase(name)) return event;
        return SomeClass.ofEvent(name);
    }
}

而且我总是可以连接 values 数组并将其从 @RestController 端点返回以填充表单。

【讨论】:

    猜你喜欢
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多