Использование Enum для фабрики в Java - лучшая практика?

20

Java позволяет нам вставлять данные и поведение в Enum. Я не хочу реализовывать фабрику непосредственно в Enum, потому что я думаю, что это не ее роль.

Но я могу поместить ссылку класса на перечисление и конструировать объект на внешнем заводе. По сравнению с традиционным образцом фабрики, какова наилучшая реализация для вас? Какое решение лучше использовать в этом случае?

Теперь, код.

Функция, используемая в обоих решениях для построения объектов. Полезно для реализации шаблона fly-weight с картой, если требуется.

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

1) С традиционным заводом:

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) С фабрикой Enum:

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());
}
    
задан airdump 10.07.2013 в 23:36
источник
  • можете ли вы привести мне пример второго в основной функции? (Я хочу увидеть использование этой фабрики), этот вопрос существует 4 года назад, все же это лучший способ? –  Saeid 11.03.2018 в 02:48

4 ответа

15

Второй - намного чище: он не нуждается в длинном блоке переключения и имеет 0 риск забыть одно из значений перечисления, как у первого.

Не всегда возможно использовать его, потому что перечисление может быть некоторым общим перечислением (например, Month ), которое не должно быть связано с фабрикой действий.

    
ответ дан JB Nizet 10.07.2013 в 23:44
источник
7

Отделить еще больше:

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 очень быстро, поэтому не беспокойтесь.

    
ответ дан ZhongYu 11.07.2013 в 01:21
источник
6

Это работает для меня:

 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();
    }
}
    
ответ дан Serg Burlaka 22.12.2016 в 12:10
источник
4

Следует избегать вызова IMO newInstance() , если это вообще возможно, так как он явно наносит ущерб некоторой защите времени компиляции, заданной java (читайте ее javadoc), и вводит новые Exception s для обработки.

Вот решение, похожее на что такое Сергей предоставлено , немного более кратким благодаря функциональным интерфейсам и ссылкам на методы.

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();
}
    
ответ дан OneWholeBurrito 06.11.2017 в 01:50
источник