问题 如何将String映射到Java中的函数?


目前,我有一堆实现了Java的Java类 Processor 界面,意味着他们都有一个 processRequest(String key) 方法。这个想法是每个班级都有一些(比方说,<10)成员 Strings,并且每个映射到该类中的方法通过 processRequest 方法,像这样:

class FooProcessor implements Processor
{
    String key1 = "abc";
    String key2 = "def";
    String key3 = "ghi";
    // and so on...

    String processRequest(String key)
    {
        String toReturn = null;
        if (key1.equals(key)) toReturn = method1();
        else if (key2.equals(key)) toReturn = method2();
        else if (key3.equals(key)) toReturn = method3();
        // and so on...

        return toReturn;
    }

    String method1() { // do stuff }
    String method2() { // do other stuff }
    String method3() { // do other other stuff }
    // and so on...
}

你明白了。

这对我来说很好,但是现在我需要一个从key到function的运行时可访问映射;不是每个功能 其实 返回一个String(一些返回void),我需要动态访问每个具有键的类中每个函数的返回类型(使用反射)。我已经有一位了解所有钥匙的经理,但是  从键到功能的映射。

我的第一直觉是使用替换此映射 if-else 用a语句 Map<String, Function>就像我在Javascript中所做的那样。但是,Java不支持一流的功能,所以我在那里运气不好。我可能会挖掘出第三方库,让我可以使用一流的功能,但我还没有看到,我怀疑我需要一个全新的库。

我也想过把这些 String 键入数组并使用反射按名称调用方法,但我看到此方法有两个缺点:

  • 我的键必须与方法命名相同 - 或者以特定的,一致的方式命名,以便将它们映射到方法名称。
  • 这似乎比Way慢 if-else 我现在的陈述。效率是一个令人担忧的问题,因为这些方法往往会被频繁调用,我希望尽量减少不必要的开销。

TL; DR: 我正在寻找一种干净,最小的开销方式来映射 String 某种程度的 Function 我可以调用和调用的对象(类似) getReturnType() 上。我特别介意使用第三方库  符合我的需要。我也不介意使用反射,尽管我非常希望每次进行方法查找时都避免使用反射 - 可能会使用一些结合了 Map 用反射。

关于获得我想要的好方法的想法?干杯!


12275
2018-04-30 15:49


起源

你不能做String to Method(java.sun.com/j2se/1.4.2/docs/api/java/lang/reflect/Method.html)?然后,您可以缓存执行所需的方法。 - Chris Dennett
@Chris - 是的,这基本上就是我在问题的最后所说的。 - Matt Ball
完成了 :) :) :) - Chris Dennett


答案:


你做不到 String 至 Method?然后,您可以缓存执行所需的方法。


1
2018-03-25 05:42





没有任何一流的独立功能,但您可以通过界面执行所需的操作。创建一个代表您的功能的界面。例如,您可能具有以下内容:

public interface ComputeString
{
    public String invoke();
}

然后你可以创建一个 Map<String,ComputeString> 像你想要的对象一开始。使用地图将比反射快得多,并且还会提供更多类型安全性,因此我建议如上所述。


7
2018-04-30 15:55



这意味着为我想要调用的每个函数都有一个实现类,这看起来很笨拙,需要为每个函数提供一些样板。对我来说听起来不是那么棒。 - Matt Ball
它完全笨重,但这是Java不能直接支持高阶函数的错误。 - Chris Conway
@Bears,是的,它是笨重的,但是你可以构造一个匿名类,这应该使它稍微不那么笨重,比如map.put(str,new ComputeString(){public String invoke(){return“blah”;}}); - Michael Aaron Safyan


虽然你不能拥有第一类函数,但是有一些匿名类可以基于一个接口:

interface ProcessingMethod {
   String method();
}

Map<String, ProcessingMethod> methodMap = new HashMap<String, ProcessingMethod>();
methodMap.put("abc", new ProcessingMethod() {
   String method() { return "xyz" }
});
methodMap.put("def", new ProcessingMethod() {
   String method() { return "uvw" }
});

methodMap.get("abc").method();

或者你可以使用Scala :-)


4
2018-04-30 15:57





这个  用一个 enum 命名函数和抽象 FunctionAdapter 调用具有可变数量的同构参数的函数而不进行反射。该 lookup()功能只是使用 Enum.valueOf,但是 Map 对于大量的功能来说可能是值得的。


1
2018-04-30 19:51





正如你所注意到的,你可以用你想做的事 反思API但是,除了你已经提出的问题之外,你还失去了Java编译器的一些好处。将你的字符串包装在一个对象中并使用 访客模式 解决你的问题?每 StringWrapper 只接受一个 Visitor 有正确的方法,或沿着这些方向的东西。


0
2018-04-30 15:51



我不认为访客模式在这里是正确的方法 - 也就是说,我没有在它上面出售。什么会 Visitor 操作?操作是什么? - Matt Ball
@Bears会吃掉你 - 当我想到这个想法时,我想象访问者访问每个String的包装器,但是再次看起来你不知道什么时候会出现String。我认为接口的想法要简单得多。 - justkt
游客?使用命令或策略模式。其他答案演示了命令模式。您可以找到模式的真实例子 这里 这样你就可以学到更多关于它们的知识。 - BalusC


使用Map,其中键是字符串,值是实现包含method()的接口的对象。这样,您就可以从地图中获取包含所需方法的对象。然后只需在对象上调用该方法即可。例如:

class FooProcessor implements Processor{

    Map<String, FooMethod> myMap;

    String processRequest(String key){
        FooMethod aMethod = myMap.getValue(key);
        return aMethod.method();
    }        
}

0
2018-04-30 16:00





关于什么 方法 反射API中的类?您可以根据名称,参数或返回类型查找类的方法。然后你只需调用Method.invoke(this,parameters)。

这与您正在谈论的JavaScript中的地图几乎相同。


0
2018-04-30 23:14