Подтвердить что ты не робот

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

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

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

Теперь, код.

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

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

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

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-стиле factory:

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());
}
4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

 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();
    }
}

Ответ 4

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

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

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();
}