如何删除对Java枚举的依赖关系';s的价值观?
[请注意差距:我知道最好的解决方案是完全取消enum,但这不是评论中提到的今天的选择,但计划在(遥远的)未来进行。] 我们有两个部署单元:前端和后端。前端使用枚举并在后端调用EJB服务,并将枚举作为参数。但是枚举经常更改,所以我们不希望后端知道它的值 字符串常量 一个可能的解决方案是使用字符串常量而不是枚举,但这会在前端引起很多小的变化。我正在寻找一个解决方案,在前端引起尽可能少的变化 包装类 另一种解决方案是使用与枚举具有相同接口的包装类。枚举成为包装器类,枚举值成为该包装器中的常量。我必须编写一些反序列化代码来确保对象标识(就像枚举一样),但我不知道这是否是一个正确的解决方案。如果使用不同的类加载器呢? 包装器类将实现一个Java接口,它将替换后端中的枚举。但是反序列化代码会在后端执行吗 包装器类的示例:如何删除对Java枚举的依赖关系';s的价值观?,java,serialization,enums,classloader,dependency-management,Java,Serialization,Enums,Classloader,Dependency Management,[请注意差距:我知道最好的解决方案是完全取消enum,但这不是评论中提到的今天的选择,但计划在(遥远的)未来进行。] 我们有两个部署单元:前端和后端。前端使用枚举并在后端调用EJB服务,并将枚举作为参数。但是枚举经常更改,所以我们不希望后端知道它的值 字符串常量 一个可能的解决方案是使用字符串常量而不是枚举,但这会在前端引起很多小的变化。我正在寻找一个解决方案,在前端引起尽可能少的变化 包装类 另一种解决方案是使用与枚举具有相同接口的包装类。枚举成为包装器类,枚举值成为该包装器中的常量。我必须编
public class Locomotion implements Serializable {
private static final long serialVersionUID = -6359307469030924650L;
public static final List<Locomotion> list = new ArrayList<Locomotion>();
public static final Locomotion CAR = createValue(4654L);
public static final Locomotion CYCLE = createValue(34235656L);
public static final Locomotion FEET = createValue(87687L);
public static final Locomotion createValue(long type) {
Locomotion enumValue = new Locomotion(type);
list.add(enumValue);
return enumValue;
}
private final long ppId;
private Locomotion(long type) {
this.ppId = type;
}
private Object readResolve() throws ObjectStreamException {
for (Locomotion enumValue : list) {
if (this.equals(enumValue)) {
return enumValue;
}
}
throw new InvalidObjectException("Unknown enum value '" + ppId + "'");
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (ppId ^ (ppId >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Locomotion)) {
return false;
}
Locomotion other = (Locomotion) obj;
if (ppId != other.ppId) {
return false;
}
return true;
}
}
公共类移动实现可序列化{
私有静态最终长serialVersionUID=-6359307469090924650L;
public static final List=new ArrayList();
公共静态最终移动车=createValue(4654L);
公共静态最终移动周期=createValue(34235656L);
公共静态最终移动英尺=createValue(87687L);
公共静态最终移动createValue(长型){
移动枚举值=新移动(类型);
列表。添加(枚举值);
返回枚举值;
}
私人最终长ppId;
私家车(长型){
this.ppId=类型;
}
私有对象readResolve()引发ObjectStreamException{
用于(移动枚举值:列表){
if(this.equals(枚举值)){
返回枚举值;
}
}
抛出新的InvalidObjectException(“未知枚举值”“+ppId+””);
}
@凌驾
公共int hashCode(){
最终整数素数=31;
int结果=1;
结果=素数*结果+(int)(ppId^(ppId>>>32));
返回结果;
}
@凌驾
公共布尔等于(对象obj){
if(this==obj){
返回true;
}
if(obj==null){
返回false;
}
如果(!(obj移动实例)){
返回false;
}
移动其他=(移动)obj;
if(ppId!=其他.ppId){
返回false;
}
返回true;
}
}
你已经有同样的问题了吗?您是如何解决的?这是一个奇怪的请求,因为我认为服务器应该知道进入数据库的内容的值,但好的,我会同意。也许你可以这样做
public enum Giant {Fee, Fi, Fo, Fum};
public void client() {
Giant giant = Giant.Fee;
server(giant);
}
public void server(Enum e) {
String valueForDB = e.name();
//or perhaps
String valueForDB = e.toString();
}
对于前端和后端之间的数据传输,都需要使用相同的类版本,因为在编组参数期间可能会进行序列化。因此,他们必须知道完全相同的枚举或您尝试使用的任何其他类。将枚举切换到其他对象也不起作用。您必须为这两个设置一个已知的类标识 因此,如果服务器应该基于某种类型的处理/计算参数值来执行操作,请使用字符串或您决定的任何其他非更改类,并将您的值放入其中:字符串、数字数组或其他任何类型
因此,如果将数据库id放入包装器对象中,服务器将能够从数据库中取出对象。但是,它们的类路径中都需要完全相同版本的包装器类。好的,我不能太精确,因为我看不到您的代码,但根据我的经验,类似这样的更改应该是外部数据,而不是枚举 我几乎总是发现,如果我将枚举中的信息外部化,那么我还必须将其他一些部分外部化,但在完成所有这些之后,我最终将分解掉许多代码 任何时候,当您实际使用枚举的值时,几乎可以肯定您正在编写重复的代码。我的意思是,如果你有像“心”,“钻石”这样的枚举 在代码中使用它们的唯一方法是使用类似于switch语句的语句:
switch(card.suit)
case Suit.HEARTS:
load_graphic(Suit.HEARTS);
// or better yet:
Suit.HEARTS.loadGraphic();
break;
case Suit.SPADES:
Suit.SPADES.loadGraphic();
...
现在,这显然是愚蠢的,但我做了愚蠢的限制,说您使用了代码中的值。我的主张是,如果不使用这些值,就不需要枚举——我们不要在代码中使用这些值,请参见:
card.suit.loadGraphic();
哇,都没了。但是突然之间,使用枚举的全部意义都消失了——取而代之的是,您放弃了整个类,而是从一个文本文件中预加载一个“Suit”工厂,其中包含4个实例,该文本文件的字符串为“Heart.png”和“Spade.png”
几乎每次使用枚举时,我都会这样分解它们
我并不是说没有任何代码可以从枚举中获益——但我在分解代码和外部化数据方面做得越好,我就越不可能真正需要它们。好的,让我看看我是否理解。你说的 “前端使用枚举并调用 后端具有 枚举作为参数。但是枚举 频繁更改,因此我们不希望 后端要知道它的值“ 当您说“values”时,我假设您指的是在枚举构造函数中传递的数值,而不是枚举常量本身 因此,这意味着前端和后端将有两个不同版本的枚举类,但其中的枚举常量是相同的 我只是假设沟通是通过RMI进行的(但这在你的帖子中并不完全清楚) 现在,连载
public class Fruit implements Serializable{
private static final long serialVersionUID = 1L;
public final Fruit ORANGE = new Fruit("orange");
public final Fruit LEMON = new Fruit("lemon");
private String name;
private Fruit(String name){
this.name = name;
}
}
public static Fruit toFruit(FruitEnum enum);
public FruitEnum valueOf(Fruit fruit);