Java枚举:实现常用方法,避免重复

时间:2016-08-22 14:29:02

标签: java enums abstraction jdk1.6 code-duplication

假设我有两个不同的枚举

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,现在无法升级。任何帮助表示赞赏。感谢。

4 个答案:

答案 0 :(得分: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

EDITED: 这与@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));
}

答案 1 :(得分:1)

您可以将实现包装到通用帮助器类中,并在所有实现中使用它。不幸的是,你必须将调用复制到帮助器中; 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.

答案 2 :(得分: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的答案。

答案 3 :(得分:0)

Helper课程非常有用。我们已经开始遇到坏工厂的问题,导致枚举依赖于订单 - 这是一个彻底的过程 -

现在我重构了所有枚举类,以便他们使用帮助程序和单个工厂。但是我通过以下方式改变了它的签名:

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

在我的枚举类中,我有一个成员定义为:

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

这样,我不必在参数中传递枚举类型,而且我不必将调用乘以 values() class.getEnumConstants()