【问题标题】:How can I map a String to a function in Java?如何将字符串映射到 Java 中的函数?
【发布时间】:2011-02-14 07:19:27
【问题描述】:

目前,我有一堆实现Processor 接口的Java 类,这意味着它们都有一个processRequest(String key) 方法。这个想法是每个类都有一些(例如,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...
}

你明白了。

这对我来说工作得很好,但现在我需要一个运行时可访问的从键到函数的映射;并非每个函数实际上都返回一个字符串(有些返回 void),我需要动态访问每个有键的类中每个函数的返回类型(使用反射)。我已经有一个了解所有键的经理,但了解从键到功能的映射。

我的第一个直觉是用 Map<String, Function> 替换使用 if-else 语句的映射,就像我在 Javascript 中所做的那样。但是,Java 不支持一流的函数,所以我不走运。我可能会挖掘一个第三方库来让我使用一流的函数,但我还没有看到任何东西,我怀疑我是否需要一个全新的库。

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

  • 我的键必须与方法命名相同 - 或以特定、一致的方式命名,以便轻松将它们映射到方法名称。
  • 这似乎比我现在的if-else 语句慢得多。效率是一个问题,因为这些方法往往会被非常频繁地调用,我想尽量减少不必要的开销。

TL; DR: 我正在寻找一种干净、开销最小的方法来将String 映射到某种Function 对象,我可以调用和调用(类似于)getReturnType() on。如果它真的符合我的需要,我并不特别介意使用第 3 方库。我也不介意使用反射,但我强烈希望避免在每次进行方法查找时都使用反射——也许使用一些将Map 与反射相结合的缓存策略。

想出一种获得我想要的东西的好方法吗?干杯!

【问题讨论】:

标签: java string reflection functional-programming


【解决方案1】:

没有任何一流的独立功能,但您可以使用接口做您想做的事情。创建一个代表您的功能的接口。例如,您可能有以下情况:

public interface ComputeString
{
    public String invoke();
}

然后,您可以首先创建一个您想要的Map<String,ComputeString> 对象。使用地图会比反射快得多,并且还会提供更多的类型安全性,所以我建议以上。

【讨论】:

  • 这意味着我要调用的每个函数都有一个实现类,这看起来很笨重,并且每个函数都需要一些样板文件。对我来说听起来并不那么棒。
  • 这完全是笨拙的,但这是Java不直接支持高阶函数的错。
  • @Bears,是的,它很笨重,但是您可以构造匿名类,这应该使它不那么笨拙,例如 map.put(str,new ComputeString(){public String invoke(){ return "废话"; }});
【解决方案2】:

虽然您不能拥有一流的功能,但有可以基于接口的匿名类:

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 :-)

【讨论】:

    【解决方案3】:

    你不能把String 转成Method 吗?然后就可以缓存需要执行的方法了。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        正如您所注意到的,您可以使用Reflection API 做您想做的事,但是除了您已经提出的问题之外,您还失去了 Java 编译器的一些好处。将您的字符串包装在一个对象中并使用Visitor pattern 解决您的问题吗?每个StringWrapper 只会接受具有正确方法的Visitor,或者类似的东西。

        【讨论】:

        • 我不认为访问者模式是正确的方法——也就是说,我不相信它。 Visitor 的作用是什么?手术是什么?
        • @Bears 会吃掉你——当我在思考这个想法时,我描绘了访问者访问每个字符串的包装器,但看起来你不知道什么时候会出现什么字符串。我认为接口的想法要简单得多。
        • 访客?使用命令或策略模式。其他答案演示了命令模式。您可以找到真实生活中的模式示例here,以便您了解更多有关它们的信息。
        【解决方案6】:

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

        class FooProcessor implements Processor{
        
            Map<String, FooMethod> myMap;
        
            String processRequest(String key){
                FooMethod aMethod = myMap.getValue(key);
                return aMethod.method();
            }        
        }
        

        【讨论】:

          【解决方案7】:

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

          这与您所说的 JavaScript 中的 Map 几乎相同。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-07-24
            • 2012-01-23
            • 1970-01-01
            • 2011-02-19
            • 2021-05-09
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多