如何删除对Java枚举的依赖关系';s的价值观?

如何删除对Java枚举的依赖关系';s的价值观?,java,serialization,enums,classloader,dependency-management,Java,Serialization,Enums,Classloader,Dependency Management,[请注意差距:我知道最好的解决方案是完全取消enum,但这不是评论中提到的今天的选择,但计划在(遥远的)未来进行。] 我们有两个部署单元:前端和后端。前端使用枚举并在后端调用EJB服务,并将枚举作为参数。但是枚举经常更改,所以我们不希望后端知道它的值 字符串常量 一个可能的解决方案是使用字符串常量而不是枚举,但这会在前端引起很多小的变化。我正在寻找一个解决方案,在前端引起尽可能少的变化 包装类 另一种解决方案是使用与枚举具有相同接口的包装类。枚举成为包装器类,枚举值成为该包装器中的常量。我必须编

[请注意差距:我知道最好的解决方案是完全取消enum,但这不是评论中提到的今天的选择,但计划在(遥远的)未来进行。]

我们有两个部署单元:前端和后端。前端使用枚举并在后端调用EJB服务,并将枚举作为参数。但是枚举经常更改,所以我们不希望后端知道它的值

字符串常量

一个可能的解决方案是使用字符串常量而不是枚举,但这会在前端引起很多小的变化。我正在寻找一个解决方案,在前端引起尽可能少的变化

包装类

另一种解决方案是使用与枚举具有相同接口的包装类。枚举成为包装器类,枚举值成为该包装器中的常量。我必须编写一些反序列化代码来确保对象标识(就像枚举一样),但我不知道这是否是一个正确的解决方案。如果使用不同的类加载器呢? 包装器类将实现一个Java接口,它将替换后端中的枚举。但是反序列化代码会在后端执行吗

包装器类的示例:

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