在 Java 中使用 Enum 进行工厂,最佳实践?

Posted

技术标签:

【中文标题】在 Java 中使用 Enum 进行工厂,最佳实践?【英文标题】:Using Enum for factory in Java, a best practice? 【发布时间】:2013-07-09 00:18:09 【问题描述】:

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

【问题讨论】:

你能给我一个 main 函数中第二个的例子吗? (我想看看这家工厂的用法),这个问题是4年前的问题,还是最好的方法吗? 【参考方案1】:

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

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

【讨论】:

【参考方案2】:

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

这里有一个类似于what Sergey provided 的解决方案,只是由于功能接口和方法引用而更加简洁。

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

【讨论】:

这是一个非常优雅的解决方案。非常感谢!【参考方案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】:

进一步解耦:

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 非常快,所以不用担心。

【讨论】:

以上是关于在 Java 中使用 Enum 进行工厂,最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章

库、“注入工厂”和扩展库的最佳实践

枚举到int最佳实践[重复]

[译] 最佳安全实践:在 Java 和 Android 中使用 AES 进行对称加密

依托于应用工厂的应用实现的最佳实践

Java 数据绑定最佳实践

10秒钟构建你自己的”造轮子”工厂! 2019年github/npm工程化协作开发栈最佳实践