枚举的每个成员的内部类?

时间:2017-11-09 19:25:20

标签: java enums abstract-class

不确定我想要的是否可能,但我正在尝试创建一个枚举,其中每个成员都有自己的内部类。这些内部类都将具有相同的名称Context,但将单独实施。

理想情况下,我希望它们可以这样使用:

private handleType (MyEnum type) {
    switch (type) {

        case ENUM_VAL1:
            MyEnum.ENUM_VAL1.Context context = new MyEnum.ENUM_VAL1.Context();
            handleContext1(context);
            break;

        case ENUM_VAL2:
            MyEnum.ENUM_VAL2.Context context = new MyEnum.ENUM_VAL1.Context();
            handleContext2(context);
            break;

        case ENUM_VAL3:
            MyEnum.ENUM_VAL3.Context context = new MyEnum.ENUM_VAL1.Context();
            handleContext3(context);
            break;

        default:
            break;
}

开放其他实现方式。但基本上我需要一个可切换的枚举,每个成员都有一个"值" (1,2,3 ......)以及将所述枚举与具有构造函数的唯一类相关联的方法。

编辑:一些背景。这将在通过JSON http请求进行通信的两个服务之间使用。请求将包含一些元数据,其中一个字段是映射到枚举的整数。上下文是POJO,但每个ENUM_VALUE都不同。本质上,上下文将被构造并序列化为JSON。这个json实际上只是一个在顶级json请求中称为上下文的String字段。在接收服务上,将在ENUM_VALUE上进行切换,其中上下文被适当地解码,然后被分派到其适当的处理程序。

EDIT2:这个枚举将在两个服务之间共享。

EDIT3:这是对我试图做的更明确的解释。

MyServiceRequest:

public class MyServiceRequest {
    String meta1;
    String meta2;
    int typeID;
    String context;
}

生成请求:

MyServiceRequest req = new MyServiceRequest();
req.meta1 = ...
req.meta2 = ...
req.typeID = MyEnum.ENUM_VALUE.getCode(); // int

MyEnum.ENUM_VALUE.Context context = new MyEnum.ENUM_VALUE.Context(); // factory would be fine as well
... // populate context
req.context = toJSON(context);
requestJSON = toJSON(req);
post(requestJSON);

解码请求:

MyServiceRequest req = ...
MyEnum type = new MyEnum(req.typeID);
switch(type) {
    case ENUM_VALUE:
        MyEnum.ENUM_VALUE.Context context = fromJSON(req.context, MyEnum.ENUM_VALUE.Context.class);
        doSomething(context);

4 个答案:

答案 0 :(得分:9)

有人认为你可以做的就是拥有你的枚举工具Supplier<Context>。现在每个项都必须声明一个get()方法来创建单独的Context子类型。

enum MyEnum implements Supplier<Context>{
   FOO{ @Override public Context get(){ return new FooContext(); } },
   BAR{ @Override public Context get(){ return new BarContext(); } }
}

这将使您的客户端代码更简单:

private void handleType (MyEnum type) {
    handleContext(type.get());
}

答案 1 :(得分:4)

为什么要使用内部类?

您可以简单地使用每个枚举常量的不同值初始化字段 context 。像:

public enum Whatever {
  A(new AContext), B... 

  private final Context context;

  private Whatever(Context context) {
    this.context = context;
 .... 

答案 2 :(得分:1)

我不会为每个枚举推荐一个单独的内部类,只是一个单独的实现。下面的内容可能是您最好的方法,那么您不必使用switch声明。因为您只需在getContext()变量上调用type

enum MyEnum{

    A(new Context(){
        // my implementation
    }),
    B(new Context(){
        // my other implementation
    }),
    ;

    private final Context context;

    MyEnum(Context context){
        this.context = context;
    }

    public Context getContext(){
        return context;
    }

    public interface Context{
        // do something
    }
}

答案 3 :(得分:1)

您所描述的最重要的问题是作用于单个枚举元素的类没有可在该元素之外解析的名称。这使得无法通过枚举值之外的new运算符实例化这样的类,或者在枚举值之外声明具有该类作为参数或返回类型的任何方法。

但是,通过声明要实现的内部类的接口类型,并提供一个工厂方法来代替用于获取实例的构造函数,您可以在很大程度上解决这个问题。例如:

enum MyEnum {
    ENUM_VAL1 {
        class Context implements MyEnum.Context {
            public void doSomething() {
                System.out.println(1);
            }
        }

        public MyEnum.Context createContext() {
            return new Context();
        }
    },
    ENUM_VAL2 {
        class Context implements MyEnum.Context {
            public void doSomething() {
                System.out.println(2);
            }
        }

        public MyEnum.Context createContext() {
            return new Context();
        }
    };

    interface Context {
        public void doSomething();
    }

    public abstract Context createContext();
}

public class EnumScope {

    private void handleContext1(MyEnum.Context context) {
        context.doSomething();
    }

    private void handleContext2(MyEnum.Context context) {
        context.doSomething();
    }

    private void handleType(MyEnum type) {
        MyEnum.Context context = type.createContext();

        switch (type) {
            case ENUM_VAL1:
                handleContext1(context);
                break;
            case ENUM_VAL2:
                handleContext2(context);
                break;
        }
    }
}

我认为这有点可疑但是 - 特别是具有特定枚举值的方法实际上属于那些枚举值。可能有一种完全不同的方法可以为您提供更好的服务,但您已经过多地描述了这个问题,我们建议这样做。

更新

在考虑了对问题的编辑和随后的评论之后,我倾向于坚持我的评估,即你提出的建议有点可疑。

退一步从更广泛的角度考虑问题。您正在生成,序列化(到JSON),反序列化和消耗多种类型的请求(目前,由显示在其中的ID代码区分)。使用具有适当属性的类来表示每种类型的请求是有意义的,包括每种类型的变化上下文数据的属性。如果存在一些有意的共性,那么这些应该实现一个描述它们的公共接口,甚至可以扩展一个共同的基类。

完成后,JSON序列化/反序列化就解决了(不止一次)问题。除非你喜欢重新发明轮子,否则我倾向于为此建议Google GSON。我需要证明我对GSON没有太多个人经验,但它很受欢迎,你会在这里看到很多关于它的问题(和答案)。你也会找到一些很好的在线教程。