Java allow us to embed data and behaviour on Enum. I don't want to implement a factory directly on an Enum, because I think this is not its role.
Java允许我们在Enum上嵌入数据和行为。我不想直接在Enum上实现工厂,因为我认为这不是它的作用。
But I can put class reference on the enum, and contruct object on an external factory. Comparing to a traditionnal factory pattern, what is the best implementation for you ? Which solution is better to use in which case ?
但我可以在枚举上放置类引用,并在外部工厂上构造对象。与传统的工厂模式相比,什么是最适合您的实施?在哪种情况下哪种解决方案更好用?
Now, the code.
现在,代码。
Function used in both solutions to construct objects. Usefull to implement fly-weight pattern with a Map if required.
两种解决方案中用于构造对象的函数。如果需要,可以使用Map实现fly-weight模式。
private Action getAction(Class<? extends Action> actionClazz) {
// logger + error handling
return actionClazz.newInstance();
}
1) With a traditionnal factory:
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) With Enum-styled factory :
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());
}
4 个解决方案
#1
15
The second one is much cleaner: it doesn't need any long switch block, and has 0 risk of forgetting one of the enum values like the first one has.
第二个更清洁:它不需要任何长开关块,并且有忘记其中一个枚举值的风险,就像第一个那样。
It's not always possible to use it, though, because the enum might be some generic enum (Month
, for example), that should not be coupled to the factory of actions.
但是,并不总是可以使用它,因为枚举可能是一些通用的枚举(例如,月),它不应该耦合到动作的工厂。
#2
7
To decouple even more:
要解耦更多:
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
is very fast so no worries.
EnumMap非常快,所以不用担心。
#3
7
This works for 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();
}
}
#4
4
IMO calling newInstance()
should be avoided if at all possible, as it blatantly defeats some of the compile time protection given by java (read its javadoc) and introduces new Exception
s to handle.
如果可能的话,应该避免IMO调用newInstance(),因为它公然违反了java给出的一些编译时保护(读取它的javadoc)并引入了新的Exceptions来处理。
Here's a solution similar to what Sergey provided, just a little more concise thanks to functional interfaces and method references.
这是一个类似于Sergey提供的解决方案,由于功能接口和方法引用,更简洁一点。
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();
}
#1
15
The second one is much cleaner: it doesn't need any long switch block, and has 0 risk of forgetting one of the enum values like the first one has.
第二个更清洁:它不需要任何长开关块,并且有忘记其中一个枚举值的风险,就像第一个那样。
It's not always possible to use it, though, because the enum might be some generic enum (Month
, for example), that should not be coupled to the factory of actions.
但是,并不总是可以使用它,因为枚举可能是一些通用的枚举(例如,月),它不应该耦合到动作的工厂。
#2
7
To decouple even more:
要解耦更多:
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
is very fast so no worries.
EnumMap非常快,所以不用担心。
#3
7
This works for 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();
}
}
#4
4
IMO calling newInstance()
should be avoided if at all possible, as it blatantly defeats some of the compile time protection given by java (read its javadoc) and introduces new Exception
s to handle.
如果可能的话,应该避免IMO调用newInstance(),因为它公然违反了java给出的一些编译时保护(读取它的javadoc)并引入了新的Exceptions来处理。
Here's a solution similar to what Sergey provided, just a little more concise thanks to functional interfaces and method references.
这是一个类似于Sergey提供的解决方案,由于功能接口和方法引用,更简洁一点。
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();
}