Utiliser L'Enum pour l'usine en Java, une bonne pratique?

Java permet d'intégrer des données et des comportements sur Enum. Je ne veux pas implanter une usine directement sur un Enum, parce que je pense que ce n'est pas son rôle.

mais je peux mettre une référence de classe sur l'enum, et contruire l'objet sur une usine externe. Par rapport à un modèle d'usine traditionnel, Quelle est la meilleure implémentation pour vous ? Quelle solution est préférable d'utiliser dans quel cas ?

maintenant, le code.

fonction utilisée dans deux solutions pour construire des objets. Utile pour mettre en œuvre le modèle de masse de la mouche avec une carte si nécessaire.

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

1) avec une usine traditionnelle:

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) avec usine enum-style:

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

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

public Action getAction(ActionEnum action) {
    return getAction(action.getClazz());
}
21
demandé sur sttaq 2013-07-11 01:36:29

4 réponses

le second est beaucoup plus propre: il n'a pas besoin de long bloc de commutateur, et a 0 risque d'oublier une des valeurs enum comme la première A.

il n'est pas toujours possible de l'utiliser, cependant, parce que l'enum pourrait être un enum Générique ( Month , par exemple), qui ne devrait pas être couplé à l'usine d'actions.

15
répondu JB Nizet 2013-07-10 21:44:42

pour découpler encore plus:

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 est très rapide, donc pas de soucis.

7
répondu ZhongYu 2013-07-10 23:21:49

ça marche pour moi:

 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();
    }
}
7
répondu Serg Burlaka 2016-12-22 11:10:30

IMO appelant newInstance() doit être évitée si possible, car il va à l'encontre de la protection de temps de compilation donnée par java (lire son javadoc) et introduit de nouveaux Exception s à gérer.

Voici une solution similaire à ce que Sergey a fourni , juste un peu plus concis grâce à des interfaces fonctionnelles et des références de méthode.

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();
}
6
répondu OneWholeBurrito 2017-11-23 16:21:14