题
我有一个大数枚举,实现这种接口:
/**
* 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);
}
但这证明是相当没有用的,因为:
- 枚举不能延长一类
- 元素的一个枚举,(SKYPE,GOOGLE_TALK,等等。) 不能延长一类
- 我无法提供默认的执行情况的getByCode(),因为DefaultCodableEnum本身不是一枚举。我试图改变DefaultCodableEnum延长java。郎。枚举,但这似乎不是允许的。
任何建议,不要依赖反射?谢谢, 别
解决方案
你可以的因素的重复代码进入一个 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());
}
}
其他提示
抽象枚举的潜在非常有用的,(而目前不允许的)。但有的建议和原的存在如果你想大堂的人在阳光添加:
http://freddy33.blogspot.com/2007/11/abstract-enum-ricky-carlson-way.html
太阳RFE:
收拾dave的代码:
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));
}
}
我有一个类似的问题与本地化成分,我写了。我的成分是设计来访问本地化的信息与enum常量,即引入资源束,不是一个困难的问题。
我发现我是复制、粘贴相同的"模板"enum代码,所有的地方。我的解决方案,以避免重复工作是一种代码生成接受XML配置文件的枚举恒定的名称和构造args.输出是Java源代码"重复"的行为。
现在,我维持的结构的文件和发电机,并不是所有的重复代码。我到处都会有枚举的源代码,现在有一种XML配置文件。我建立的脚本中检测出的日期产生的文件和引用的代码生成创造枚举的代码。
你可以看到这种成分 在这里,.该模板,我是复制、粘贴是考虑到出入 XSLT样式表.的 代码生成器 跑的样式转变。一个 输入文件 是很简洁的比枚举产生的源码。
禾田,
格雷格
不幸的是,我不认为有一种方法来这样做。您最好的选择亲干练地被放弃在emums共和使用常规类扩展和静态的成员。否则,得到的用于复制的那个代码。对不起。
创建一个类安全的实用程序类将载枚举的代码:
在接下来:
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()方法是在一个地方。它可能是不错的包装所有的例外情况在单一的异常太:)
我这里有另一个解决方案:
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方法,但这些方法, 只委派器.
似乎你们是实际执行运行时间类型的信息。Java提供了这样一个语言功能。
我建议你看看RTTI或反射。
我不认为这是可能的。然而,可以使用的枚举的值(String name)法,如果你要用枚举,值的名字作为你的代码。
如何对一个静态的一般方法?你可以重复利用它在你的枚举的getByCode()方法,或只是使用它。我总是用户整数id我枚举的,所以我getById()方法只有具有做这样做:回值()[id]。这是一个很大更快、更简单。
如果你真的想继承,不要忘了,你可以 执行枚举自己的图案, 像坏老Java1.4天。
关于关闭,因为我得到了你想要什么是创造一个模板,在用浏览器,这将'实施'的通用代码(采用枚举的值(String name))。不完美的,但工作得很好。
在特定情况下,getCode()/getByCode(String代码)的方法似乎非常关闭(委婉地说)的行为toString()/值(String值)的方法提供的所有枚举。为什么你不想使用它们?
另一个解决方案将不把任何东西进入枚举本身,而只是提供一个双向的地图Enum <->的代码,用于每一枚举。你可以比如使用 ImmutableBiMap 从Google的收藏品这一点。
这样有没有重复代码。
例如:
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();
在我看来,这将是最简单的方法,没有反映并没有增加任何额外的包装你的枚举。
你创建的一个接口,你enum实现:
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);