2016-08-22 55 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()