2013-07-10 2 views
18

Java ci permettono di incorporare dati e comportamenti su Enum. Non voglio implementare una fabbrica direttamente su una Enum, perché penso che questo non sia il suo ruolo.Utilizzo di Enum per factory in Java, una best practice?

Ma posso mettere riferimento alla classe sull'enumerazione e contromettere l'oggetto su una fabbrica esterna. Confrontando con un modello di fabbrica tradizionale, qual è l'implementazione migliore per te? Quale soluzione è meglio usare nel qual caso?

Ora, il codice.

Funzione utilizzata in entrambe le soluzioni per la costruzione di oggetti. Utile per implementare un modello di peso mosca con una mappa se necessario.

private Action getAction(Class<? extends Action> actionClazz) { 
    // logger + error handling 
    return actionClazz.newInstance(); 
} 

1) Con una fabbrica traditionnal:

public enum ActionEnum { 
    LOAD_DATA, 
    LOAD_CONFIG; 
} 

public Action getAction(ActionEnum action) { 
    switch (action) { 
    case LOAD_CONFIG: 
     return getAction(ActionLoadConfig.class); 
    case LOAD_DATA: 
     return getAction(ActionLoadData.class); 
    } 
} 

2) Con fabbrica Enum stile:

public enum ActionEnum { 
    LOAD_DATA(ActionLoadConfig.class), 
    LOAD_CONFIG(ActionLoadData.class); 

    public ActionEnum(Class<? extends Action> clazz){...} 
    public getClazz() {return this.clazz} 
} 

public Action getAction(ActionEnum action) { 
    return getAction(action.getClazz()); 
} 
+0

puoi darmi un esempio del secondo in una funzione principale? (Voglio vedere l'utilizzo di questa fabbrica), questa domanda è per 4 anni fa, è ancora il modo migliore? – Saeid

risposta

15

La seconda è molto più pulito: non ha bisogno di alcun tempo commuta blocco e ha il rischio di dimenticare uno dei valori enumerati come il primo.

Non è sempre possibile utilizzarlo, tuttavia, poiché l'enumerazione potrebbe essere un enum generico (Month, ad esempio), che non deve essere associato alla produzione di azioni.

6

disaccoppiare ancora di più:

static final EnumMap<ActionEnum, Class<? extends Action>> enumToClass = new EnumMap<>(); 
static 
{ 
    enumToClass.put(ActionEnum.LOAD_DATA, ActionLoadData.class); 
    etc... 
} 


public Action getAction(ActionEnum action) 
{ 
    return getAction(enumToClass.get(action)); 
} 

EnumMap è molto veloce quindi nessuna preoccupazione.

6

questo funziona per me:

enum ActionEnum 
    { 
     LOAD_DATA { 

     @Override 
     public ActionLoadData getInstance() { 
      return new ActionLoadData(); 
     } 

    }, 
    LOAD_CONFIG { 

     @Override 
     public ActionLoadConfig getInstance() { 
      return new ActionLoadConfig(); 
     } 

    }; 

    public abstract ILightBulb getInstance(); 
} 

class ActionFactory 
{ 
    public Action getAction(ActionEnum action) 
    { 
     return action.getInstance(); 
    } 
} 
2

IMO chiamando newInstance() dovrebbero essere evitati se possibile, in quanto sconfigge palesemente alcuni dei protezione in tempo di compilazione data dal java (leggere il suo javadoc) e introduce nuovi Exception s gestire.

Ecco una soluzione simile a what Sergey provided, solo un po 'più concisa grazie alle interfacce funzionali e ai riferimenti dei metodi.

public enum ActionEnum { 
    LOAD_DATA(ActionLoadData::new), 
    LOAD_CONFIG(ActionLoadConfig::new) 

    private Supplier<Action> instantiator; 

    public Action getInstance() { 
    return instantiator.get(); 
    } 

    ActionEnum(Supplier<Action> instantiator) { 
    this.instantiator = instantiator; 
    } 
} 

public Action getAction(ActionEnum action) { 
    return action.getInstance(); 
}