从Generic类调用枚举静态方法

时间:2013-12-19 13:13:17

标签: java generics inheritance architecture implementation

我想进行重构,并希望创建一个通用类来避免重复代码。我们的项目中有很多XXXCriteriaValidator,我们想要创建一个唯一的类来替换它们。

问题是这个类要求Enum中的静态方法的一行。在这里你会看到。这或多或少是我正在努力实现的目标:

public class GenericCriteriaValidator<T extends ¿SomeKindOfEnumInterface?> 
                                               implements CriterionVisitor {

    protected Errors errors;

    public Errors getErrors() {
        return this.errors;
    }

    /* 
     * Some code around here 
     */

    protected void doVisit(final PropertyCriterion criterion) {
        if (criterion == null) {
            this.errors.reject("error.criterion.null");
        } else {
            if (criterion.getOperator() == null) {
                this.errors.reject("error.operator.null");
            }

            // Validates property (exception thrown if not exists)
            T.fromString(criterion.getName()); // The problem is this call here!!
                                               // Not saying this compiles, just looking
                                               // how to do something equivalent
        }
    }
}

T总是不同的Enum。典型的枚举是这样的:

public enum ContactCriteria implements CriteriaInterface<ContactCriteria>  {
                                       // ^ This interface is added by me
                                       //   for the enum being called in the previous                           class

    CONTACT_ID("this.id"),
    CONTACT_COMPANY_ID("this.companyId"),
    CONTACT_NAME("this.name"),
    CONTACT_EMAIL("this.email"),
    CONTACT_PHONE_NUMBER("this.phoneNumber"),
    CONTACT_ORDER("this.order"),

    private final String alias;

    ContactCriteria(final String alias) {
        this.alias = alias;
    }

    public String getAlias() {
        return this.alias;
    }

    public static ContactCriteria fromString(final String name) {
        ContactCriteria result = null;

        if (name != null) {
            result = Enum.valueOf(ContactCriteria.class, name);
        }
        return result;
    }

    public ContactCriteria returnThis() {
        return this;
    }

}

最后,我正在寻找第一个类的接口来接受T的fromString方法。我想它应该类似于:

public interface CriteriaInterface<T> {
    static T fromString(String name);
    // ^ This static is important
}

我没有找到任何与Enum类似的帖子或策略。我知道Enum可以实现一个接口,但不知道如何获得它。

请帮忙。提前致谢

4 个答案:

答案 0 :(得分:1)

您应该首先在Java接口中不允许使用静态方法。

接口背后的概念强烈反对静态元素,因为它们属于类而不是对象。

因此,如果枚举中的静态方法只是一个分配给它的容器,但不应该通过任何其他关系连接它。

这里有什么不好的设计,你试着用enum来表达你不应该那么专注的东西,为什么你这么挣扎。

问题是如果enum instanceCriteriaInterface,那么为什么要按名称自行提供呢interface Messanger { String getMessage(); }

Enum包含可以表示接口但不能是通用的“常量”的定义。这就是为什么枚举可以实现接口。

表示您可以定义界面

enum Messages {
 INFO
 WARNING;
}

尝试将其应用于枚举

   enum Messages implements Messanger {
     INFO,
     WARNING;

     private String message;

     @Override
     public String getMessage() {
          return message;
     }
}

您有两种选择,

首先,创建一个

的字段
   enum Messages implements Messanger {
     INFO("Info"),  //We create an instance of class as we call the constructor 
     WARNING("Warnig") //We create an instance of class as we call the constructor 
     ;

     private final String message;

     public Message(String message) {
       this.messsage = message;
     }

     @Override
     public String getMessage() {
          return message;
     }
}

然后你必须添加构造函数来设置字段

enum

当我们在{{1}}的正文中声明实例时,您必须提供创建它所需的所有信息。假设enum允许泛型,那么就是你应该声明它的地方。

答案 1 :(得分:0)

如果您的CriteriaInterface上有静态方法,则不应该

CriteriaIntervace.fromString("")

因为静态方法属于一个类(在这种情况下是CriteriaIntervace)而不是一个对象?

答案 2 :(得分:0)

你不能在界面中放置静态方法,泛型等对此没有直接影响。接口定义了对象实例的方法,静态方法不是实例接口的一部分,它们是类接口的一部分。

最简单的解决方法是向GenericCriteriaValidator提供工厂对象,或者将其设为抽象并提供:

abstract T getEnum(String name);

然后,每个实现都可以为它正在使用的枚举实现getEnum。

答案 3 :(得分:0)

嗯,一般来说,泛型类型已被删除,除了明确告诉GenericCriteriaValidator应该应用哪种验证逻辑之外,你没有其他机会。您可能希望抽象某种类型的接收并使用工厂模式,这样就可以为fromString方法定义接口。

这会导致类似这样的事情:

public interface CriteriaInterface<T> {
  static class Factory<U> {
    U fromString(String name);
  }
}

但是,我在你的例子中并没有看到这样做的好处。只需要CriteriaInterface<T>的实例作为GenericCriteriaValidator的构造函数参数,并在此界面中定义某种validate方法。

但是,如果你真的想要避免这种情况,那就有一个解决方案。可以读取其他类的超类的泛型类型(这是相当hacky,需要反射,我不推荐它,但有些库喜欢这种方法)。这要求您在使用泛型类时始终声明一个匿名子类:

class GenericCriteriaValidator<T extends Enum<?>> implements CriterionVisitor {

  private final Method criteria;

  public GenericCriteriaValidator() {
    ParameterizedType parameterizedType = (ParameterizedType) getClass()
       .getGenericSuperclass();
    try {
      criteria = ((Class<?>) parameterizedType.getActualTypeArguments()[0])
          .getMethod("fromString", String.class);
      criteria.setAccessible(true);
    } catch (NoSuchMethodException e) {
      throw new IllegalArgumentException(e);
    }
  }

  @SuppressWarning("unchecked")
  private CriteriaInterface<?> invokeFromString(String value) {
    try {
      return (CriteriaInterface<?>) criteria.invoke(null, value);
    } catch (IllegalAccessException e) {
      throw new IllegalStateException(e);
    } catch (InvocationTargetException e) {
      throw new IllegalArgumentException(e);
    }
  }

  // Your other code goes here.

}

请注意,您需要将GenericCriteriaValidator实例化为匿名子类:

new GenericCriteriaValidator<ContactCriteria>() { }; // mind the braces!

正如我所说。我不觉得这很直观,而且肯定不是“Java方式”,但你可能仍然想要考虑它。