java - 如何使用枚举避免反射

标签 java reflection enums interface

我最近问了一个关于我使用反射的一些代码的问题,一位想帮助我解决这个问题的人提到我不应该像这样使用反射,并且有更好的方法来做到这一点。

所以我有一个用于在外部系统中搜索的界面:

public interface ReferenceController {

  public Map<String, ReferenceElement> searchElements(String searchField, List<String> searchItems, SystemStage systemStage) throws Exception;

  public String getStateMapping(String value);

  public Boolean isAvailable(SystemStage systemStage) throws Exception;
}

我有一个 ENUM,在其中声明我拥有哪些外部系统以及使用此接口(interface)的类的命名方式。因此,如果任何其他程序员想要实现一个新的外部系统,他只需填充接口(interface)并将两个值放入此 ENUM 和 tada 中,它就应该可以工作。

所以我使用反射的部分是

public static void performSingleSearch(ReferenceSystem referenceSystem, String searchField, List<String> searchValues, SystemStage systemStage) throws Exception {

    if(!isAvailable(referenceSystem, systemStage)) return;
    Map<String, ReferenceElement> result = new HashMap<>();
    try {
        Class<?> classTemp = Class.forName(referenceSystem.getClassname());
        Method method = classTemp.getMethod("searchElements", String.class , List.class, SystemStage.class);
        result = (Map<String, ReferenceElement>) method.invoke(classTemp.newInstance(), searchField, searchValues, systemStage);
    } catch (Exception e) { 
        return;
    }
    if(result != null) orderResults(result, referenceSystem);
}

在 ENUM 中有一个函数 getClassname,它用 fqcn 进行应答。 枚举看起来像这样:

public enum ReferenceSystem {
    UCMDB    (refSystems.ucmdb.UcmdbFunctions.class),
    PROIPS   (refSystems.proips.ProIPSFunctions.class),
    KV       (refSystems.kv.KvFunctions.class),
    FISERVICE(refSystems.fiservice.FiServiceFunctions.class),
    COMMAND  (refSystems.command.CommandFunctions.class),
    FII          (refSystems.fii.FiiFunctions.class);

    private Class<?> clazz;

    private ReferenceSystem(Class<?> controllerClass) {
        this.clazz = controllerClass;
    }

    public String displayName() {
        ResourceBundle bundle = ResourceBundle.getBundle("EnumI18n", Locale.GERMAN);
        return bundle.getString(toString()); 
    }

    public String localizedDisplayName(Locale locale) {
        ResourceBundle bundle = ResourceBundle.getBundle("EnumI18n", locale);
        return bundle.getString(toString()); 
    }

    public Class<?> getClassname() { return clazz; }
}

我已经根据@jhamon的回答进行了更改。

但是当我尝试时出现错误

classTemp.newInstance().searchElemets(...)

因为它不知道 searchElemts()。

所以这里的其他用户说有可能将接口(interface)实现到枚举中,然后我就不必反射(reflect)了。 谁能告诉我怎么做,因为我不知道,也不知道在哪里或搜索什么。 谢谢

最佳答案

似乎所有搜索引擎都有一个通用方法searchElements并且它是在界面中定义的

既然知道了,为什么不直接调用这个方法,而不是先寻找它呢。 -> 不再需要反射来查找方法。

public interface ReferenceController {

    public Map<String, ReferenceElement> searchElements(String searchField, List<String> searchItems, SystemStage systemStage) throws Exception;

    public String getStateMapping(String value);

    public Boolean isAvailable(SystemStage systemStage) throws Exception;
}

不要将类名作为字符串存储在枚举中,而是存储 .class -> 不再通过反射来查找该类。

public static void performSingleSearch(ReferenceSystem referenceSystem, String searchField, List<String> searchValues, SystemStage systemStage) throws Exception {

    if(!isAvailable(referenceSystem, systemStage)) return;
    Map<String, ReferenceElement> result = new HashMap<>();
    try {
        Class<?> classTemp = referenceSystem.getClazz();
        result = ((ReferenceController) classTemp.newInstance()).searchElements(searchField, searchValues, systemStage);
    } catch (Exception e) { 
        return;
    }
    if(result != null) orderResults(result, referenceSystem);
}

关于java - 如何使用枚举避免反射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56599562/

相关文章:

javascript - 使用jquery和html5显示存储在arraylist中的数据

java - JTextPane 中消失的组件

java - 如何在类路径中包含 hbase-site.xml

java - Gson 使用通用代码将枚举序列化和反序列化为整数

c - 在为所有枚举值定义大小写后,编译器仍然说 : "control reaches end of non-void function"

java - 选择不包含主要类型。 eclipse 错误

ruby - 获取构造函数的参数名称

java - 是否可以将检索到的类对象(通过反射)转换为接口(interface)?

c# - 从 .NET 中的堆栈帧获取参数值?

c# - 使用 ValueInjecter 在枚举之间映射