我有大量实现此接口的枚举:

/**
 * Interface for an enumeration, each element of which can be uniquely identified by it's code
 */
public interface CodableEnum {

    /**
     * Get the element with a particular code
     * @param code
     * @return
     */
    public CodableEnum getByCode(String code);

    /**
     * Get the code that identifies an element of the enum
     * @return
     */
    public String getCode();
}

一个典型的例子是:

public enum IMType implements CodableEnum {

    MSN_MESSENGER("msn_messenger"),
    GOOGLE_TALK("google_talk"),
    SKYPE("skype"),
    YAHOO_MESSENGER("yahoo_messenger");

    private final String code;

    IMType (String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }   

    public IMType getByCode(String code) {
        for (IMType e : IMType.values()) {
            if (e.getCode().equalsIgnoreCase(code)) {
                return e;
            }
        }
    }
}

可以想象,这些方法在CodableEnum的所有实现中几乎完全相同。 我想消除这种重复,但坦率地说不知道如何。 我尝试使用如下的类:

public abstract class DefaultCodableEnum implements CodableEnum {

    private final String code;

    DefaultCodableEnum(String code) {
        this.code = code;
    }

    public String getCode() {
        return this.code;
    }   

    public abstract CodableEnum getByCode(String code);  
}

但事实证明这是无用的,因为:

  1. 枚举不能扩展类
  2. 枚举元素(SKYPE,GOOGLE_TALK等)不能扩展类
  3. 我无法提供getByCode()的默认实现,因为DefaultCodableEnum本身不是Enum。 我尝试更改DefaultCodableEnum以扩展java.lang.Enum,但似乎不允许这样做。

任何不依赖反思的建议? 谢谢,唐

===============>>#1 票数:13 已采纳

您可以将重复的代码分解为CodeableEnumHelper类:

public class CodeableEnumHelper {
    public static CodeableEnum getByCode(String code, CodeableEnum[] values) {
        for (CodeableEnum e : values) {
            if (e.getCode().equalsIgnoreCase(code)) {
                return e;
            }
        }
        return null;
    }
}

每个CodeableEnum类仍然必须实现getByCode方法,但该方法的实际实现至少已集中到一个地方。

public enum IMType implements CodeableEnum {
    ...
    public IMType getByCode(String code) {
        return (IMType)CodeableEnumHelper.getByCode(code, this.values());
    } 
}

===============>>#2 票数:7

抽象枚举可能非常有用(目前不允许)。 但是,如果您想在Sun中为某个人添加游戏来添加它,则存在一个提案和原型:

http://freddy33.blogspot.com/2007/11/abstract-enum-ricky-carlson-way.html

Sun RFE:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570766

===============>>#3 票数:5

整理戴夫的代码:

public class CodeableEnumHelper {
    public static <E extends CodeableEnum> E getByCode(
        String code, E[] values
    ) {
        for (E e : values) {
            if (e.getCode().equalsIgnoreCase(code)) {
                return e;
            }
        }
        return null;
    }
}

public enum IMType implements CodableEnum {
    ...
    public IMType getByCode(String code) {
        return CodeableEnumHelper.getByCode(code, values());
    } 
}

或者更有效率:

public class CodeableEnumHelper {
    public static <E extends CodeableEnum> Map<String,E> mapByCode(
        E[] values
    ) {
        Map<String,E> map = new HashMap<String,E>();
        for (E e : values) {
            map.put(e.getCode().toLowerCase(Locale.ROOT), value) {
        }
        return map;
    }
}

public enum IMType implements CodableEnum {
    ...
    private static final Map<String,IMType> byCode =
        CodeableEnumHelper.mapByCode(values());
    public IMType getByCode(String code) {
        return byCode.get(code.toLowerCase(Locale.ROOT));
    } 
}

===============>>#4 票数:2

我写了一个与本地化组件类似的问题。 我的组件旨在访问具有索引到资源包的枚举常量的本地化消息,而不是硬问题。

我发现我正在复制并粘贴相同的“模板”枚举代码。 我避免重复的解决方案是一个代码生成器,它接受带有枚举常量名称和构造函数args的XML配置文件。 输出是具有“重复”行为的Java源代码。

现在,我维护配置文件和生成器,而不是所有重复的代码。 我到处都有枚举源代码,现在有一个XML配置文件。 我的构建脚本检测过时的生成文件,并调用代码生成器来创建枚举代码。

你可以在这里看到这个组件。 我正在复制和粘贴的模板被分解为XSLT样式表 代码生成器运行样式表转换。 与生成的枚举源代码相比, 输入文件非常简洁。

HTH,
格雷格

===============>>#5 票数:1

我有另一个解决方案:

interface EnumTypeIF {
String getValue();

EnumTypeIF fromValue(final String theValue);

EnumTypeIF[] getValues();

class FromValue {
  private FromValue() {
  }

  public static EnumTypeIF valueOf(final String theValue, EnumTypeIF theEnumClass) {

    for (EnumTypeIF c : theEnumClass.getValues()) {
      if (c.getValue().equals(theValue)) {
        return c;
      }
    }
    throw new IllegalArgumentException(theValue);
  }
}

诀窍是内部类可用于保存“全局方法”。

对我来说工作得很好。 好的,你必须实现3个方法,但这些方法只是委托人。

===============>>#6 票数:1

不幸的是,我认为没有办法做到这一点。 你最好的选择是完全放弃emums并使用传统的类扩展和静态成员。 否则,习惯于复制该代码。 抱歉。

===============>>#7 票数:1

创建一个类型安全的实用程序类,它将按代码加载枚举:

界面归结为:

public interface CodeableEnum {
    String getCode();
}

实用程序类是:

import java.lang.reflect.InvocationTargetException;


public class CodeableEnumUtils {
    @SuppressWarnings("unchecked")
    public static <T extends CodeableEnum>  T getByCode(String code, Class<T> enumClass) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        T[] allValues = (T[]) enumClass.getMethod("values", new Class[0]).invoke(null, new Object[0]);
        for (T value : allValues) {
            if (value.getCode().equals(code)) {
                return value;
            }
        }
        return null;
}

}

演示用法的测试用例:

import junit.framework.TestCase;


public class CodeableEnumUtilsTest extends TestCase {
    public void testWorks() throws Exception {
    assertEquals(A.ONE, CodeableEnumUtils.getByCode("one", A.class));
      assertEquals(null, CodeableEnumUtils.getByCode("blah", A.class));
    }

enum A implements CodeableEnum {
    ONE("one"), TWO("two"), THREE("three");

    private String code;

    private A(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }   
}
}

现在,您只复制getCode()方法,并且getByCode()方法位于一个位置。 将所有异常包装在单个RuntimeException中可能会很好:)

===============>>#8 票数:0

另一种解决方案是不将任何内容放入枚举本身,只为每个枚举提供双向映射Enum < - >代码。 例如,您可以使用Google Collections中的ImmutableBiMap

这样就没有重复的代码了。

例:

public enum MYENUM{
  VAL1,VAL2,VAL3;
}

/** Map MYENUM to its ID */
public static final ImmutableBiMap<MYENUM, Integer> MYENUM_TO_ID = 
new ImmutableBiMap.Builder<MYENUM, Integer>().
put(MYENUM.VAL1, 1).
put(MYENUM.VAL2, 2).
put(MYENUM.VAL3, 3).
build();

===============>>#9 票数:0

在我看来,这将是最简单的方法,没有反射,也没有为你的枚举添加任何额外的包装。

您创建了枚举实现的接口:

public interface EnumWithId {

    public int getId();

}

然后在帮助器类中,您只需创建一个类似这样的方法:

public <T extends EnumWithId> T getById(Class<T> enumClass, int id) {
    T[] values = enumClass.getEnumConstants();
    if (values != null) {
        for (T enumConst : values) {
            if (enumConst.getId() == id) {
                return enumConst;
            }
        }
    }

    return null;
}

然后可以像这样使用此方法:

MyUtil.getInstance().getById(MyEnum.class, myEnumId);

===============>>#10 票数:0

看起来您实际上正在实现运行时类型信息。 Java将此作为语言功能提供。

我建议你查看RTTI或反思。

===============>>#11 票数:0

我不认为这是可能的。 但是,如果要使用枚举值的名称作为代码,则可以使用enum的valueOf(String name)方法。

===============>>#12 票数:0

静态泛型方法怎么样? 您可以在枚举的getByCode()方法中重用它,或者直接使用它。 我总是为我的枚举使用整数id,所以我的getById()方法只做这样做:return values()[id]。 它更快更简单。

===============>>#13 票数:0

如果您真的想要继承,请不要忘记您可以自己实现枚举模式 ,就像在糟糕的旧Java 1.4天中一样。

===============>>#14 票数:0

尽可能接近你想要的是在IntelliJ中创建一个“实现”通用代码的模板(使用enum的valueOf(String name))。 不完美,但效果很好。

===============>>#15 票数:0

在您的特定情况下,getCode()/ getByCode(String code)方法似乎非常封闭(委婉地说)所有枚举提供的toString()/ valueOf(String value)方法的行为。 你为什么不想用它们?

  ask by Dónal translate from so

未解决问题?本站智能推荐:

2回复

我们不能在枚举内运行main方法吗? [重复]

这个问题已经在这里有了答案: Java找不到主类 5个答案 我看过一个视频,其中main()可以在enum运行。 我正在尝试做同样的事情,但是没有用。 这是我的代码 输出 (代码可以正常编译) Error: Could not find or lo
3回复

如何在Java中枚举的字段上进行迭代? [重复]

这个问题已经在这里有了答案: 用于遍历Java 10答案中 的枚举的“ for”循环 我有这个Java 枚举 : 包含我必须使用XPATH进行处理的XML文件的字段(但是目前这并不重要) 我必须遍历所有这些枚举字段,才能对每个枚举字段进行操作。
1回复

您将如何在Ruby中实现此Java枚举类? [重复]

这个问题已经在这里有了答案: 如何在Ruby中实现枚举? 26个答案 我从Java类获得以下代码: 作为Ruby的新手,我试图找出在Ruby中实现的方法。 越简单越好。 我根据这里的一些帖子尝试了以下内容,但似乎无法完成。 我希望该类具有一个pars
5回复

Java枚举和具有私有构造函数的类之间有什么区别? [重复]

这个问题在这里已有答案: Java枚举与具有公共静态最终字段的类相比有什么优势? 15个答案 我试图理解Java枚举是如何工作的,我得出的结论是它与普通的Java类非常相似,它的构造函数被声明为private。 我刚刚得出这个结论,并不是基于太多的想法,但我
7回复

枚举:为什么? 什么时候?

我是一名即将毕业的计算机科学专业的学生,​​在我的整个编码生涯中,我发现很少使用枚举的实例,除了典型情况下(例如代表标准纸牌的面孔)。 您是否知道在日常编码中使用枚举的任何巧妙方法? 为什么枚举如此重要?在什么情况下应该能够确定建立枚举是最好的方法?
5回复

枚举中的间距相等吗?

我正在上一堂Java课,而本节是关于枚举的。 我的枚举中有这个: 这在我的Java类中将其打印出来: 打印出: 请参见右侧的Silverado的“ Red”和“ 1996”(因为“ Silverado”比其他单词长)的样子? 那么,我该如何解决它,使长字的细节与其余字
3回复

如何实现枚举类型的某些方法

我是编程和Java的新手,目前正在学习枚举类型。 我创建了一个枚举类型的Card ,它将每张卡的值存储在一副纸牌中,例如2 = 2、3 = 3 ... Ace =11。每张图片卡具有相同的值10。 我正在尝试实现方法getPrevious() ,该方法将返回列表中的上一个枚举值。
4回复

枚举列表删除问题

谁能帮我解决这个问题? 以下是结果- 请帮忙-为什么会这样,我还检查了哈希码?
1回复

参数化Java枚举

如何在Java中参数化一个或多个enum值? 我有3个非常相似的enum : ActiveStateGreenRed , ActiveStateGreenOrange和ActiveStateGreenYellow 。 如何制作“通用” enum (我们称其为ActiveState )
6回复

Java枚举方法

我想声明一个枚举Direction,它具有一个返回相反方向的方法(以下语法不正确,即,不能实例化枚举,但它说明了我的观点)。 这在Java中可行吗? 这是代码: