什么是模拟可扩展枚举行为的合成正确方法?

huangapple go评论73阅读模式
英文:

What'd be the synthetically correct way of imitating extendable enum behavior?

问题

传统上当我有一个枚举时

```java
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 implements Serializable {

    private long id;

    private String name;

    ...
}

并且 WebhookEvent 是从数据库中填充的。我不想在最终产品中创建一个类来持有这些事件名称,比如:

public class EnabledEvent {

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

    ...
}

因为这会从两个不同的地方控制应用程序的行为。相反地,我希望能够在数据库中有新条目时立即返回这些常量/字段。基本上,我想要能够模仿根据数据库条目扩展常量/枚举的行为。是否有正确的方法在程序中实现这一点?


<details>
<summary>英文:</summary>

Traditionally, when I have an enum:

```java
public enum SomeEnum implements Serializable {
    TYPE_1,
    TYPE_2;
}

or a class:

public class Country {

    public static final Country SOME_COUNTRY = new Country(&quot;someCode&quot;);

    private final String code;

    ...
}

In a controller, I return these values to populate some selects:

@RestController(...)
public List&lt;Field&gt; getFields() {

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

    // or

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

Currently, I'm working on a webhook library which could be imported by some final products. Some of the event names come from the library itself but some of them are not present in the library (but in the final product code):

Webhook class looks like this:

public class Webhook {

    private String url;

    private List&lt;WebhookEvent&gt; events;

    ...
}

and WebhookEvent is as follows:

public class WebhookEvent Serializable {

    private long id;

    private String name;

    ...
}

and the WebhookEvents are populated from the database. I don't want to create a holding class in the final product like:

public class EnabledEvent {

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

    ...
}

because that'd be controlling the behavior of the application from 2 different points. But instead, I want to be able to return these constants/fields as soon as there's a new entry in the database. Basically I want to be able to imitate the behavior of extend the constants/enums based on the entries in the database. Is there a correct way to programmatically achieve this?

答案1

得分: 0

在我们的情况下,有许多常量需要进行验证。这些常量文件开始堆积起来。因此,我们不得不想出一种不同的方式,最终创建了一个专门用于常量的单独表格,这样您就可以添加、移除或禁用不需要的常量,而无需重新编译您的代码(尽管如果存在依赖情况,则必须重新编译)。

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

稳定、危急、已故、康复和NA

以及以下的TEST_RESULT状态:

测试等待、测试阴性和测试阳性

表格将如下所示:

------------------------------------------------------------------------
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
}
英文:

In our case there were many constants that we had to validate. This constant files started to pile up. So, we had to devise a different way and ended up creating a separate table only for constants, so you can add or remove/disable the not required once without the need to recompile your code(though you have to, if there is a dependent case).

For instance, assume that you have the following patient status (STATUS):

STABLE, CRITICAL, DECEASED, RECOVERED and NA

and the following states for TEST_RESULT:

TEST_PENDING, TEST_NEGATIVE and TEST_POSITIVE

The table would look like:

------------------------------------------------------------------------
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=&quot;constant_enum&quot;)
public class ConstantEnum implements Serializable {
	private static final long serialVersionUID = 1L;

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

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

}

答案2

得分: 0

我最终移除了与数据库的连接,并在类内部定义了静态变量,同时使用一个静态的 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("无法将值:%s 转换为有效的 %s 对象", 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 端点返回以填充表单。

英文:

I've ended up removing the connection with the database, and defining static variables within the class itself, with a static ofValue method to create objects:

public class SomeClass implements Serializable {

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

    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(&quot;Couldn&#39;t convert value : %s into a valid %s object&quot;, name, SomeClass.class.getName()));
    }
}

this way, it is expandable as follows:

public class ExtendedSomeClass extends SomeClass implements Serializable {

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

    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);
    }
}

and I can always concatenate values arrays and return it from a @RestController endpoint to populate forms.

huangapple
  • 本文由 发表于 2020年10月26日 22:17:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/64538914.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定