Java 将枚举值与类字段匹配

Java 将枚举值与类字段匹配,java,oop,java-8,enums,switch-statement,Java,Oop,Java 8,Enums,Switch Statement,我在JAVA中有一个enum和POJO类。在枚举类中,每个枚举值都与POJO类的变量匹配。。。然后我想在两个类之间创建一个关系 枚举类: public enum MyEnum { FIELD1, FIELD2, FIELD3, ... } POJO类: public class MyPojo { private String field1; private String field2_not_ref; private String field3;

我在JAVA中有一个enum和POJO类。在枚举类中,每个枚举值都与POJO类的变量匹配。。。然后我想在两个类之间创建一个关系

枚举类:

public enum MyEnum
{
   FIELD1,
   FIELD2,
   FIELD3,
   ...
}
POJO类:

public class MyPojo
{
   private String field1;
   private String field2_not_ref;
   private String field3;
   ...
}
然后,当我尝试匹配两个类的这些字段时,我实现了如下代码:

public String matchMethod(MyEnum myenum)
{
  switch(myenum)
  {
   case FIELD1:
      return field1;
   case FIELD2:
      return field2_not_ref;
    ...
  }
}
我认为这不是一个好的/明确的解决办法。有什么建议吗?

有多种选择(包括使用),但在简单的情况下,如果字段都是相同类型的(这里是
字符串),我的建议是将感兴趣的值存储在

类MyPojo{
私有最终EnumMap字段=新EnumMap(MyEnum.class);
公共字符串匹配方法(MyEnum MyEnum){
返回字段.get(myenum);
}
public void setField1(字符串值){
fields.put(MyEnum.FIELD1,value);//例如
}
}

此解决方案仅适用于
静态
字段,因为枚举总是
静态

我可以想象的一种方式是:

public enum MyEnum
{
   private String field;

   public String getField()
   { return this.field; }


   MyEnum(String field)
   {
      this.field = field;
   }

   FIELD1(field1),
   FIELD2(field2),
   FIELD3(field3),
   ...
}
如果需要,您甚至可以将其设置为通用:

public enum MyEnum<T>
{
   private T field;

   public T getField()
   { return this.field; }


   MyEnum(T field)
   {
      this.field = field;
   }

   FIELD1(field1),
   FIELD2(field2),
   FIELD3(field3),
   ...
}
公共枚举MyEnum
{
私人T场;
公共T getField()
{返回this.field;}
髓鞘(T区)
{
this.field=字段;
}
字段1(字段1),
字段2(字段2),
字段3(字段3),
...
}
还有一种方法:

在枚举中定义抽象方法,并覆盖每个枚举字段:

public enum MyEnum {
    FIELD1 {
        @Override
        public String getFromPojo(MyPojo myPojo) {
            return myPojo.getField1();
        }
    },
    FIELD2 {
        @Override
        public String getFromPojo(MyPojo myPojo) {
            return myPojo.getField2();
        }
    },
    FIELD3 {
        @Override
        public String getFromPojo(MyPojo myPojo) {
            return myPojo.getField3();
        }
    };

    public abstract String getFromPojo(MyPojo myPojo);
}

对于类
MyPojo
为字段定义getter:

还定义方法
matchMethod
,使其能够处理对枚举的责任(如果您愿意,这不是强制性的,因为枚举可以自己解析字段)

现在,在“main”方法中,您可以使用以下方法:

 MyPojo p1 = new MyPojo("p1", "p2", "p3");
 MyPojo p2 = new MyPojo("k1", "k2", "k3");

 System.out.println(MyEnum.FIELD1.getFromPojo(p1));
 System.out.println(MyEnum.FIELD2.getFromPojo(p1));
 System.out.println(MyEnum.FIELD3.getFromPojo(p1));

 System.out.println(MyEnum.FIELD1.getFromPojo(p2));
 System.out.println(MyEnum.FIELD2.getFromPojo(p2));
 System.out.println(MyEnum.FIELD3.getFromPojo(p2));

 // in addition, if you've defined 'matchMethod' on POJO
 System.out.println(p1.matchMethod(MyEnum.FIELD1));
 System.out.println(p1.matchMethod(MyEnum.FIELD2));
 System.out.println(p1.matchMethod(MyEnum.FIELD3));

 System.out.println(p2.matchMethod(MyEnum.FIELD1));
 System.out.println(p2.matchMethod(MyEnum.FIELD2));
 System.out.println(p2.matchMethod(MyEnum.FIELD3));     
这张照片是:

p1
p2
p3
k1
k2
k3
// and optionally...
p1
p2
p3
k1
k2
k3
a
b
c
x
y
z

你可以使用反射。以下是一个例子:

public String matchMethod(MyEnum myenum, Map<MyEnum, String> enumToFieldMap) throws NoSuchFieldException, IllegalAccessException {
    String customFieldName = enumToFieldMap.get(myenum);
    if (customFieldName == null) { // custom field name not found, use default mapping
        return (String) this.getClass().getDeclaredField(myenum.name().toLowerCase()).get(this);
    } // custom field name found in config
    return (String) this.getClass().getDeclaredField(customFieldName).get(this);
}

public String matchMethod(MyEnum myEnum) throws NoSuchFieldException, IllegalAccessException {
    return matchMethod(myEnum, Collections.EMPTY_MAP);
}
和通用接口:

public interface Pojo {
}
声明新的
Pojo
(s)现在变得更简单、更清晰,也更具可读性(至少对某些人来说)。在实际映射(配置)完成的地方也很明显

一个简单的方法可以将它们全部规则化:

public String matchMethod(MyEnum myEnum, Pojo myPojo) throws IllegalAccessException {
        for (Field field : myPojo.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(MyEnumRef.class) && field.getAnnotation(MyEnumRef.class).value() == myEnum) {
                field.setAccessible(true);
                return (String) field.get(myPojo);
            }
        }
        return "";
    }
使用哪种
Pojo
实现并不重要。添加新POJO时没有开销。例如:

private void run() throws IllegalAccessException {
    System.out.println(">>" + matchMethod(MyEnum.FIELD2, new MyPojo("f1", "f2", "f3")));
    System.out.println(">>" + matchMethod(MyEnum.FIELD1, new MyOtherPojo("o1", "o2")));
}

为了避免反射,这可能会比在枚举上定义方法更慢,更简洁,您可以创建一个枚举,其中的字段是使用
MyPojo
并返回
String
的函数:

public enum MyEnum {
    FIELD1(MyPojo::getField1),
    FIELD2(MyPojo::getField2),
    FIELD3(MyPojo::getField3);

    private final Function<MyPojo, String> getField;

    MyEnum(Function<MyPojo, String> getField) {
        this.getField = getField;
    }
}
如果您不想使用
apply
方法将其用作
函数
变量,可以在en enum上创建一个函数,即:

public enum MyEnum {
    FIELD1(MyPojo::getField1),
    FIELD2(MyPojo::getField2),
    FIELD3(MyPojo::getField3);

    private final Function<MyPojo, String> getField;

    MyEnum(Function<MyPojo, String> getField) {
        this.getField = getField;
    }

    String getFieldFromMyPojo(MyPojo myPojo) { return getField.apply(myPojo); }
}

为了简洁起见,省略了getter和setter。

这里还有另一种方法,它有一个间接级别(注册表),但不修改枚举

这需要Java 8+,因为它使用lambda表达式:

import java.util.EnumMap;
import java.util.function.Function;

enum MyEnum {
  FIELD1, FIELD2, FIELD3;
}

class MyPojo {
  private String field1, field2, field3;

  public MyPojo(String f1, String f2, String f3) {
    this.field1 = f1;
    this.field2 = f2;
    this.field3 = f3;
  }
  private static EnumMap<MyEnum, Function<MyPojo, String>> registry = new EnumMap(MyEnum.class);
  static {
    registry.put(MyEnum.FIELD1, p -> p.field1);
    registry.put(MyEnum.FIELD2, p -> p.field2);
    registry.put(MyEnum.FIELD3, p -> p.field3);
  }

  public String matchMethod(MyEnum e) {
    return registry.get(e).apply(this);
  }
}

class Main {
  public static void main(String[] args) {
    MyPojo p1 = new MyPojo("a", "b", "c");
    MyPojo p2 = new MyPojo("x", "y", "z");
    System.out.println(p1.matchMethod(MyEnum.FIELD1));
    System.out.println(p1.matchMethod(MyEnum.FIELD2));
    System.out.println(p1.matchMethod(MyEnum.FIELD3));

    System.out.println(p2.matchMethod(MyEnum.FIELD1));
    System.out.println(p2.matchMethod(MyEnum.FIELD2));
    System.out.println(p2.matchMethod(MyEnum.FIELD3));
  }
}

什么时候设置字段1,2,3的值?@azro,在我的main方法中,…mymain方法(MyPojo MyPojo,MyEnum MyEnum){…对象匹配结果=MyPojo.matchMethod(MyEnum);…}我看得对吗,你希望POJO字段是可变的?或者这些字段应该是不可变的?我的意思是,在
MyPojo
中更改值所应用的映射帽是否正确?@janhold,问题很清楚。我需要匹配枚举字段和POJO字段。因此,我会像这样使用它
newmypojo.getFieldByEnum(myEnum)->返回匹配字段
;这与不可变/可变的事物无关。这不起作用:两个POJO可以有一个值用于
FIELD1
,等等。你完全正确。这只适用于静态字段。。。。我更正了答案这看起来与SOLID Prensiple(打开以进行扩展,关闭以进行修改)和耦合内聚性不兼容?因此,从enum调用POJO类对我来说不是一个好选择。这取决于您的用例,目前MyPojo和MyEnum已经耦合:从enum中删除FIELD3,您必须更改POJO;向Pojo添加一个新字段,可能还需要更改
MyEnum
。我已经尝试促进java语法功能,所有其他解决方案都将包括一个间接层:映射等等。当然,您可以选择所有可能与枚举不匹配的名称。我投票支持第二种选择,即在枚举内部使用apply。OP的全部想法不是每次都不调用MyEnum.FIELD2或其他特定的枚举类型吗?甚至@Sha提出的转换比这种方法更通用。@PiotrNiewinski你是说,问题中的整个转换比简单地编写
myenum.getFieldFromMyPojo(myPojo)
?@Andronicus一点也不,我是说这可能表明OP在寻找更通用的答案,至少有
matchMethod
的签名提示soHmm。“然后我想在两个类之间创建一个关系。”这让我可以自由地设计enum以了解实体。
public enum MyEnum {
    FIELD1(MyPojo::getField1),
    FIELD2(MyPojo::getField2),
    FIELD3(MyPojo::getField3);

    private final Function<MyPojo, String> getField;

    MyEnum(Function<MyPojo, String> getField) {
        this.getField = getField;
    }
}
public static void main(String[] args) {
    MyPojo myPojo = new MyPojo("f1", "f2", "f3");
    System.out.println(MyEnum.FIELD2.getGetField().apply(myPojo));
}
public enum MyEnum {
    FIELD1(MyPojo::getField1),
    FIELD2(MyPojo::getField2),
    FIELD3(MyPojo::getField3);

    private final Function<MyPojo, String> getField;

    MyEnum(Function<MyPojo, String> getField) {
        this.getField = getField;
    }

    String getFieldFromMyPojo(MyPojo myPojo) { return getField.apply(myPojo); }
}
public static void main(String[] args) {
    MyPojo myPojo = new MyPojo("f1", "f2", "f3");
    System.out.println(MyEnum.FIELD2.getFieldFromMyPojo(myPojo));
}
import java.util.EnumMap;
import java.util.function.Function;

enum MyEnum {
  FIELD1, FIELD2, FIELD3;
}

class MyPojo {
  private String field1, field2, field3;

  public MyPojo(String f1, String f2, String f3) {
    this.field1 = f1;
    this.field2 = f2;
    this.field3 = f3;
  }
  private static EnumMap<MyEnum, Function<MyPojo, String>> registry = new EnumMap(MyEnum.class);
  static {
    registry.put(MyEnum.FIELD1, p -> p.field1);
    registry.put(MyEnum.FIELD2, p -> p.field2);
    registry.put(MyEnum.FIELD3, p -> p.field3);
  }

  public String matchMethod(MyEnum e) {
    return registry.get(e).apply(this);
  }
}

class Main {
  public static void main(String[] args) {
    MyPojo p1 = new MyPojo("a", "b", "c");
    MyPojo p2 = new MyPojo("x", "y", "z");
    System.out.println(p1.matchMethod(MyEnum.FIELD1));
    System.out.println(p1.matchMethod(MyEnum.FIELD2));
    System.out.println(p1.matchMethod(MyEnum.FIELD3));

    System.out.println(p2.matchMethod(MyEnum.FIELD1));
    System.out.println(p2.matchMethod(MyEnum.FIELD2));
    System.out.println(p2.matchMethod(MyEnum.FIELD3));
  }
}
a
b
c
x
y
z