Использование 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());
}
Ответы
Ответ 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();
}