28

Java 允许我们在 Enum 上嵌入数据和行为。我不想直接在 Enum 上实现工厂,因为我认为这不是它的作用。

但是我可以将类引用放在枚举上,并在外部工厂上构造对象。与传统的工厂模式相比,最适合您的实现方式是什么?在哪种情况下使用哪种解决方案更好?

现在,代码。

两种解决方案中用于构造对象的函数。如果需要,可用于使用 Map 实现 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)使用枚举式工厂:

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

4 回答 4

19

第二个更简洁:它不需要任何长的 switch 块,并且像第一个一样忘记其中一个枚举值的风险为 0。

但是,并不总是可以使用它,因为枚举可能是一些通用枚举(Month例如),不应该与动作工厂耦合。

于 2013-07-10T21:44:42.013 回答
19

newInstance()如果可能的话,应该避免IMO 调用,因为它公然破坏了 java 提供的一些编译时保护(阅读它的 javadoc)并引入了新Exception的 s 来处理。

这是一个类似于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();
}
于 2017-11-06T00:50:41.490 回答
17

这对我有用:

 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();
    }
}
于 2016-12-22T11:10:30.747 回答
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非常快,所以不用担心。

于 2013-07-10T23:21:49.207 回答