2013-01-18 9 views
5

Utworzyłem Enum, aby zdefiniować określone akcje. Programowanie z zewnętrznego interfejsu API Aby wyrazić tę akcję, muszę użyć Integer. Właśnie dlatego dodałem pole instancji całkowitej do mojego Enum. Powinno to być zgodne z Efektywną Javą Joshua Blocha, zamiast polegać na ordinal() lub kolejności stałych Enum przy użyciu values()[index].Utwórz metodę fabryki wyliczeniowej z unikalnej wartości instancji

public enum Action { 

    START(0), 

    QUIT(1); 

    public final int code; 

    Protocol(int code) { 
     this.code = code; 
    } 
} 

uzyskać wartość całkowitą what z API i teraz chcę utworzyć wartość Enum z niego, w jaki sposób można zaimplementować to w najbardziej rodzajowe mody?

Oczywiście dodanie takiej metody fabrycznej nie będzie działać. Nie można utworzyć instancji Enum.

Action valueOf(int what) { 
    return new Action(what); 
} 

Oczywiście zawsze mogę utworzyć instrukcję switch-case i dodać wszystkie możliwe kody i zwrócić odpowiednią stałą. Ale chcę uniknąć definiowania ich w dwóch miejscach w tym samym czasie.

Odpowiedz

5

Jeśli masz zamiar mieć wiele z nich można użyć HashMap<Integer, Action>:

private static final Map<Integer, Action> actions = new HashMap<>(values().size, 1); 

static { 
    for (Action action : values()) 
     actions.put(action.code, action); 
} 

// ... 

public static Action valueOf(int what) { 
    return actions.get(what); 
} 

Jest to przydatne, jeśli masz zamiar mieć dużą liczbę Action wartości ponieważ jest wyszukiwanie HashMap O (1).

+0

Można zainicjować mapę o odpowiednim rozmiarze: 'new HashMap <> (Action.values ​​(). Length, 1);' (nie będzie miało znaczenia, jeśli nie ma zbyt wielu wartości, ale to nie kosztuje cokolwiek to robi). – assylias

+0

@assylias Zabawne, zajrzałem do kodu źródłowego i konstruktor faktycznie ignoruje współczynnik obciążenia: * Zauważ, że ta implementacja ignoruje loadFactor; zawsze wykorzystuje współczynnik obciążenia 3/4. Upraszcza to kod i ogólnie poprawia wydajność. * –

+0

Nie wiedziałem tego - interesujące. – assylias

1

Jeżeli jesteś pewien, że kody będą zawsze sekwencyjny i od 0 to najbardziej efektywny rozwiązaniem byłoby

public enum Action { 
    START(0), 

    QUIT(1); 

    public static final Action[] ACTIONS; 
    static { 
     ACTIONS = new Action[values().length]; 
     for(Action a : values()) { 
     ACTIONS[a.code] = a; 
     } 
    } 

    public final int code; 

    Protocol(int code) { 
     this.code = code; 
    } 
} 
0

bym osobiście keep it simple (YAGNI) i użyć wartości porządkowej ale :

  • chciałbym zachować logikę w wyliczenia, aby upewnić się, że kod na zewnątrz nie wie o tym szczegółowo realizacji i nie polegać na nim
  • i wou ld upewnij się, że mam test, który się nie powiedzie, jeśli coś się zepsuje (tj. gdy numery nie zaczynają się od 0 lub nie są przyrostowe)

kod ENUM:

public enum Action { 

    START(0), 
    QUIT(1); 
    private final int code; 

    Action(int code) { 
     this.code = code; 
    } 

    public int getCode() { 
     return code; 
    } 

    public static Action of(int code) { 
     try { 
      return Action.values()[code]; 
     } catch (IndexOutOfBoundsException e) { 
      throw new IllegalArgumentException("not a valid code: " + code); 
     } 
    } 
} 

testu

@Test 
public testActionEnumOrder() { 
    int i = 0; 
    for (Action a : Action.values()) { 
     assertEquals(a.getCode(), i++); 
    } 
} 

Jeżeli zmienisz QUIT(1) do QUIT(2) na przykład , test się nie powiedzie. Kiedy tak się stanie, możesz użyć HashMap lub pętli odnośnika.

+0

Interesujące. Nie preferowałbym używania kodu, który jest bardziej prawdopodobny do zerwania z powodu zmian w kodzie, jeśli nie jest to prawdą. Ale nie zastanawiałem się nad wyborem pierwszego i popieram go testowym przypadkiem. –

+0

@MaxRhan Jeśli obawiasz się, że test może nie zostać uruchomiony, możesz nawet włączyć sprawdzanie w statycznym bloku inicjalizatora, aby był uruchamiany za każdym razem, gdy klasa jest ładowana. Wszystko, co przełamie projekt, zostanie szybko zauważone. – assylias

Powiązane problemy