英文:
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("someCode");
private final String code;
...
}
In a controller, I return these values to populate some selects:
@RestController(...)
public List<Field> 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<WebhookEvent> events;
...
}
and WebhookEvent
is as follows:
public class WebhookEvent Serializable {
private long id;
private String name;
...
}
and the WebhookEvent
s 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("event.name");
...
}
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="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
}
答案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("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()));
}
}
this way, it is expandable as follows:
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);
}
}
and I can always concatenate values
arrays and return it from a @RestController
endpoint to populate forms.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论