2016-08-22 57 views
2

比方说,我有两个型动物枚举Java的枚举:实现常用的方法,避免重复

public enum SomeEnumClass { 

    private static final SomeEnumClass[] mValues = SomeEnumClass .values(); 
    ONE(1), TWO(2), THREE(3); 

} 

public enum OtherEnumClass { 
    private static final OtherEnumClass[] mValues = OtherEnumClass .values(); 
    Monday(1), Tuesday(2), Wednesday(3), Thrusday(4), Friday(5), Saturday(6), Sunday(7) 

} 

枚举有公共的数据类型,他们携带(在这里,一个int),并在其名称不同和可能值的数量。

对于每个枚举,我有几个方法来实现,它们是严格相同的。例如:

 public static OtherEnumClass getCell(int index) 
    { 
     if (index < OtherEnumClass .mValues.length) 
     { 
      return OtherEnumClass .mValues[index];    
     } 
     throw new IllegalArgumentException("Invalid " + OtherEnumClass .class.getSimpleName() + " value: " + index); 
    } 

我想找到一种避免重复的方法,就像我会用抽象类一样。但到目前为止,我一无所有。

我们正在使用java 1.6,现在无法升级。任何帮助表示赞赏。谢谢。

+0

枚举不能扩展类,也不另一种枚举,所以要么你写的方法,每进行一次(理想情况下使日e enum实现一个定义该方法的接口),或者将代码写入枚举之外。 – Aaron

回答

1

您的代码示例有点让人误解,因为它返回的常数与序号相同,而不是具有相同属性值的常量。为了抽象搜索具有属性值的常量,必须抽象属性,例如

interface TypeWithIntProperty { 
    int getProperty(); 
} 
enum Number implements TypeWithIntProperty { 
    ONE(1), TWO(2), THREE(3); 

    private final int value; 

    Number(int value) { 
    this.value=value; 
    } 
    public int getProperty() { 
    return value; 
    } 
} 
enum DayOfWeek implements TypeWithIntProperty { 
    Monday(1), Tuesday(2), Wednesday(3), Thrusday(4), Friday(5), Saturday(6), Sunday(7); 

    private final int value; 

    DayOfWeek(int value) { 
    this.value=value; 
    } 
    public int getProperty() { 
    return value; 
    } 
} 

public class Helper { 
    public static <E extends Enum<E>&TypeWithIntProperty> 
       E getEnumItem(Class<E> type, int value) { 
    for(E constant: type.getEnumConstants()) 
     if(value == constant.getProperty()) 
     return constant; 
    throw new IllegalArgumentException("no constant with "+value+" in "+type); 
    } 
} 

DayOfWeek day=Helper.getEnumItem(DayOfWeek.class, 7); 
Number no=Helper.getEnumItem(Number.class, 2); 

如果属性有不同的类型,可以使接口通用:

interface TypeWithIntProperty<T> { 
    T getProperty(); 
} 
enum Number implements TypeWithIntProperty<String> { 
    ONE, TWO, THREE; 

    public String getProperty() { 
    return name().toLowerCase(); 
    } 
} 
enum DayOfWeek implements TypeWithIntProperty<Integer> { 
    Monday(1), Tuesday(2), Wednesday(3), Thrusday(4), Friday(5), Saturday(6), Sunday(7); 

    private final int value; 

    DayOfWeek(int value) { 
    this.value=value; 
    } 
    public Integer getProperty() { 
    return value; 
    } 
} 

public class Helper { 
    public static <E extends Enum<E>&TypeWithIntProperty<P>,P> 
        E getEnumItem(Class<E> type, P value) { 
    for(E constant: type.getEnumConstants()) 
     if(value.equals(constant.getProperty())) 
     return constant; 
    throw new IllegalArgumentException("no constant with "+value+" in "+type); 
    } 
} 

DayOfWeek day=Helper.getEnumItem(DayOfWeek.class, 7); 
Number no=Helper.getEnumItem(Number.class, "two"); 

一个更清洁,更详细(下Java 6)的替代品是的财产抽象从类型具有属性分开:

interface Property<T,V> { 
    V get(T owner); 
} 
enum Number { 
    ONE, TWO, THREE; 
    static final Property<Number,String> NAME=new Property<Number,String>() { 
    public String get(Number owner) { return owner.getName(); } 
    }; 

    public String getName() { 
    return name().toLowerCase(); 
    } 
} 
enum DayOfWeek { 
    Monday(1), Tuesday(2), Wednesday(3), Thrusday(4), Friday(5), Saturday(6), Sunday(7); 
    static final Property<DayOfWeek,Integer> INDEX=new Property<DayOfWeek,Integer>() { 
    public Integer get(DayOfWeek owner) { return owner.getIndex(); } 
    }; 

    private final int index; 

    DayOfWeek(int value) { 
    this.index=value; 
    } 
    public int getIndex() { 
    return index; 
    } 
} 
public class Helper { 
    public static <E extends Enum<E>,P> 
        E getEnumItem(Class<E> type, Property<E,P> prop, P value) { 
    for(E constant: type.getEnumConstants()) 
     if(value.equals(prop.get(constant))) 
     return constant; 
    throw new IllegalArgumentException("no constant with "+value+" in "+type); 
    } 
} 

DayOfWeek day=Helper.getEnumItem(DayOfWeek.class, DayOfWeek.INDEX, 7); 
Number no=Helper.getEnumItem(Number.class, Number.NAME, "two"); 

这一点在Java 8简单得多,你可以实现PropertyDayOfWeek::getIndexNumber::getName,而不是内部类,对另一方面,由于我们没有受益于Java 6中的单一方法接口,因此我们可以通过使用可以提供功能的抽象基类将其变为优势,现在甚至可以使用缓存:

abstract class Property<T extends Enum<T>,V> { 
    final Class<T> type; 
    final Map<V,T> map; 
    Property(Class<T> type) { 
    this.type=type; 
    map=new HashMap<V, T>(); 
    for(T constant: type.getEnumConstants()) 
    { 
     T old = map.put(get(constant), constant); 
     if(old!=null) 
     throw new IllegalStateException("values not unique: "+get(constant)); 
    } 
    } 
    abstract V get(T owner); 
    T getConstant(V value) { 
    T constant=map.get(value); 
    if(constant==null) 
     throw new IllegalArgumentException("no constant "+value+" in "+type); 
    return constant; 
    } 
} 
enum Number { 
    ONE, TWO, THREE; 
    static final Property<Number,String> NAME=new Property<Number,String>(Number.class) { 
    public String get(Number owner) { return owner.getName(); } 
    }; 

    public String getName() { 
    return name().toLowerCase(); 
    } 
} 
enum DayOfWeek { 
    Monday(1), Tuesday(2), Wednesday(3), Thrusday(4), Friday(5), Saturday(6), Sunday(7); 
    static final Property<DayOfWeek,Integer> INDEX 
       =new Property<DayOfWeek,Integer>(DayOfWeek.class) { 
    public Integer get(DayOfWeek owner) { return owner.getIndex(); } 
    }; 

    private final int index; 

    DayOfWeek(int value) { 
    this.index=value; 
    } 
    public int getIndex() { 
    return index; 
    } 
} 

DayOfWeek day=DayOfWeek.INDEX.getConstant(7); 
Number no=Number.NAME.getConstant("two"); 
+0

我正在使用助手类,它工作得很好。我可以在这里集中代码进行几次枚举。我认为整体的代码仍然很混乱,但我想这是我能做的最好的。 问题是什么意思&&TypeWithIntProperty>? 它为什么不是逗号? – Zangdar

+0

它被称为*交叉类型*。 “E”的类型必须是'enum'(扩展'Enum ')*和*它必须在同一类型中实​​现'TypeWithIntProperty'。逗号用于声明多个类型参数,但是这是具有多个约束的单个类型参数。 – Holger

+0

非常感谢这个精度! – Zangdar

1

你可以这样做:

public enum SomeEnumClass { 

    ONE, TWO, THREE; 

} 

public enum OtherEnumClass { 

    Monday, Tuesday, Wednesday, Thrusday, Friday, Saturday, Sunday 

} 

public static <E extends Enum> E getEnumItem(Class<E> type, int index){ 
    E[] values = type.getEnumConstants(); 
    if (index >= 0 && index < values.length){ 
     return values[index]; 
    } else { 
     throw new IllegalArgumentException("..."); 
    } 
} 

public static void main(String[] args) { 
    System.out.println(getEnum(SomeEnumClass.class, 0)); 
    System.out.println(getEnum(OtherEnumClass.class, 3)); 
    System.out.println(getEnum(SomeEnumClass.class, 2)); 
    System.out.println(getEnum(OtherEnumClass.class, 6)); 
} 

它打印:

ONE 
Thrusday 
THREE 
Sunday 

编辑: 这是一个类似想法@dasblinkenlight

public enum SomeEnumClass { 

    ONE, TWO, THREE; 

    public static SomeEnumClass getCell(int index) { 
     return Utility.getEnumItem(SomeEnumClass.class, index); 
    } 
} 

public enum OtherEnumClass { 

    Monday, Tuesday, Wednesday, Thrusday, Friday, Saturday, Sunday; 

    public static OtherEnumClass getCell(int index) { 
     return Utility.getEnumItem(OtherEnumClass.class, index); 
    } 
} 

public static class Utility { 

    public static <E extends Enum> E getEnumItem(Class<E> type, int index) { 
     E[] values = type.getEnumConstants(); 
     if (index >= 0 && index < values.length) { 
      return values[index]; 
     } else { 
      throw new IllegalArgumentException("..."); 
     } 
    } 
} 

public static void main(String[] args) { 
    System.out.println(Utility.getEnumItem(SomeEnumClass.class, 0)); 
    System.out.println(Utility.getEnumItem(OtherEnumClass.class, 3)); 
    System.out.println(Utility.getEnumItem(SomeEnumClass.class, 2)); 
    System.out.println(Utility.getEnumItem(OtherEnumClass.class, 6)); 
} 
+0

这将在这种情况下工作,但是我会有一些方法,这取决于枚举实际是什么。所以虽然你的“getEnumItem”要为任何枚举工作,但另一种方法将返回一个int或一个字符串基于枚举包含的成员不会。 这可能是一个解决方案,但它不会像我希望的那样安全 – Zangdar

+0

@Zangdar编辑! –

0

你可以用你的实现成一个通用的帮助类,并在所有的实现中使用它。不幸的是,你将不得不将电话复制到助手中; Java的默认方法8个解决这个问题,但你不能利用它们,因为你被限制到Java 6

// Helper owns the static members that you used to add to your enums directly 
class CellHelper<T> { 
    final T[] mValues; 
    final Class<T> cls; 
    // Helper needs Class<T> to work around type erasure 
    public CellHelper(T[] values, Class<T> c) { 
     mValues = values; 
     cls = c; 
    } 
    public T getCell(int index) { 
     if (index < mValues.length) { 
      return mValues[index];    
     } 
     throw new IllegalArgumentException("Invalid " + cls.getSimpleName() + " value: " + index); 
    } 
} 

enum SomeEnumClass { 
    ONE(1), TWO(2), THREE(3); 
    SomeEnumClass(int n){} 
    // This variable hosts your static data, along with shared behavior 
    private static final CellHelper<SomeEnumClass> helper = new CellHelper(SomeEnumClass.values(), SomeEnumClass.class); 
    // Delegate the calls for shared functionality to the helper object 
    public static SomeEnumClass getCell(int i) {return helper.getCell(i);} 
} 

enum OtherEnumClass { 
    Monday(1), Tuesday(2), Wednesday(3), Thrusday(4), Friday(5), Saturday(6), Sunday(7); 
    OtherEnumClass(int n){} 
    private static final CellHelper<OtherEnumClass> helper = new CellHelper(OtherEnumClass.values(), OtherEnumClass.class); 
    public static OtherEnumClass getCell(int i) {return helper.getCell(i);} 
} 

Demo.

0

你可以用一个接口:实施

public interface Indexed<E extends Enum> { 

    default public E getByIndex(int index) { 
     if (!this.getClass().isEnum()) { 
      //not implemented on enum, you can do as you like here 
     } 
     Enum<?>[] vals = (Enum<?>[]) this.getClass().getEnumConstants(); 
     if (index < 0 || index >= vals.length) { 
      //illegal arg exception 
     } 
     return (E) vals[index]; 
    } 

} 

然后:

public enum MyEnum implements Indexed<MyEnum> { 
    ONE, 
    TWO, 
    THREE, 
    ; 
} 

另外要注意,不是提供那些我手动指定,您可以使用Enum#ordinal

这是一个仅限于Java 8的解决方案,因为在以前的Java版本中没有默认的方法。此外,这有一个尴尬/不利的用法,因为它会是一个实例方法(尽管如果你愿意,你可以使它成为静态的)。

对于较早的版本,您需要一种方法来提供类类型,因为没有真正为其提供枚举的方法,您可以在上面使用David的答案。

+1

OP说:_我们正在使用java 1.6,现在不能升级._ –

+0

好吧,rip。这也是一个缺陷,因为它是非静态的。为了改进它,只是想把这个想法当作一个选项。 – Rogue

+0

感谢您的这一点,但我也必须补充说,我不能摆脱枚举成员,在我的例子中是一个int,但在我的代码实际上是一个状态枚举或字符串。 – Zangdar

0

助手类是真的heplful。我们已经开始与坏的工厂有问题,导致枚举依赖于订单 - 这是一个总体模型 -

现在我重构了所有枚举类,以便它们使用助手和单个工厂。不过,我改变了它的签名方式如下:

public static <E extends Enum<E> & IEnumWithValue> E factory(final E[] iConstants, int iValue) throws IllegalArgumentException 

在我的枚举类我定义为这样一个成员:

private static final MyEnum[] mValues = MyEnum.values(); 

这样,我没有通过枚举类型的参数,我没有呼叫繁衍值()class.getEnumConstants()