2017-01-17 12 views
5

Mam kilka stałe teksty z name własności i byName metody, która jest mniej więcej tak dla nich wszystkich:Faktoring się metodę występujący w wielu teksty stałe

public static Condition byName(String name) throws NotFoundException { 
    for (Condition c : values()) { 
     if (c.name.equals(name)) { 
      return c; 
     } 
    } 

    throw new NotFoundException("Condition with name [" + name + "] not found"); 
} 

Ponieważ metoda byName jest powielany w różnych teksty stałe, Chciałbym to złożyć w jednym miejscu i uniknąć duplikowania kodu.

Jednakże:

  • wyliczenia nie można rozszerzyć klasę abstrakcyjną
  • Java8 interfejsy z metod domyślnych nie może uzyskać dostępu do metody values()

wiem, może to prawdopodobnie być wykonane z AspectJ, ale I” Nie należy raczej wprowadzać kompilacji w czasie do czegoś prostego, a Spring AOP (który mam pod ręką, ponieważ jest to projekt wiosenny) pozwala tylko na wiązanie z istniejącymi metodami i nie dodawanie nowych.

Jakieś inne możliwe rozwiązanie, aby dodać wspólną metodę do wyliczenia?

+0

nie można zawinąć te teksty stałe do innej klasy (jeden za enum class) ... A ta klasa rozszerzyłaby klasę abstrakcyjną o tę metodę "byName"? –

Odpowiedz

7

Oto co zrobiłem w tej samej sytuacji:

public interface EnumWithNames { 
    String getName(); 

    static <E extends EnumWithNames> E byName(Class<E> cls, String name) { 
     for (E value : cls.getEnumConstants()) { 
      if (Objects.equals(value.getName(), name)) return value; 
     } 
     throw new IllegalArgumentException("cannot identify " + cls.getName() + " value by name " + name); 
    } 
} 

public enum Condition implements EnumWithNames { 
    private String name; 
    ... 

    @Override 
    public String getName() { return name; } 
} 

I kiedy trzeba znaleźć wartość enum wg nazwy zadzwonić:

Condition c = EnumWithNames.byName(Condition.class, "Name 1"); 

Uwaga cls.getEnumConstants() jest taka sama jak values().

+2

Można nawet wymagać, aby 'E' było także Enumem:' & EnumWithNames> '. Umożliwi to użycie wywołania 'values ​​()'. – Thirler

+0

@Thirler Możesz zawęzić typ 'T', ale nie możesz wywołać niejawnej metody' values ​​() '. – Flown

+3

Deklaracja 'E' jako' & EnumWithNames> 'nie zezwala na wywoływanie metody' values ​​() ', ale uniemożliwia osobom wywołującym przekazywanie typu innego niż ,, za29", dla którego ta metoda nie działałaby . – Holger

0

Można utworzyć pewną statyczną metodę użyteczności i użyć metody użytecznej w samym wyliczeniu. Nadal masz trochę duplikacji. Nie wiem o wiele lepiej, jak to zrobić.

public static T staticByName(String name, Class<T> clazz) { 
    for (T c : values()) { 
     if (c.name.equals(name)) { 
      return c; 
     } 
    } 

    throw new NotFoundException("Condition with name [" + name + "] not found"); 
} 

i wyliczenia

public static Condition byName(String name){ 
    return Utility.staticByName(name, Condition.class); 
} 

Alternatywnie, można umieścić elementy w mapie na Enum instancji, aby nieco bardziej wydajny.

Powyższy kod jest nieprzetestowany, więc prawdopodobnie trzeba będzie go zmodyfikować, aby działał na elementach typu Enums, ale ma to znaczenie przekrojowe.

+0

Myślę, że masz lepszy pomysł, moje rozwiązanie jest całkiem bezużyteczne, ponieważ potrzebujesz instancji wyliczenia. Jest tylko jeden problem, nazywasz "wartości" na niczym. –

2

Wydaje się, że jestem trochę późno do partii tutaj .. ale tutaj jest to, co mam w miejscu tym przypadku:

static interface Nameable { 

     static <T extends Enum<T>> T byName(Class<T> clazz, String name) { 

      return EnumSet.allOf(clazz) 
       .stream() 
       .filter(i -> i.name().equals(name)) 
       .findFirst() 
       .orElseThrow(IllegalArgumentException::new); 
    } 
} 
Powiązane problemy