【问题标题】:Java equivalent of function mapping in PythonJava 等价于 Python 中的函数映射
【发布时间】:2009-06-01 11:48:37
【问题描述】:

在 python 中,如果我想根据输入调用一些函数,我可以这样做:

lookup = {'function1':function1, 'function2':function2, 'function3':function3}
lookup[input]()

也就是说我有一个映射到函数的函数名字典,并通过字典查找调用该函数。

如何在java中做到这一点?

【问题讨论】:

    标签: java python function


    【解决方案1】:

    Java 没有一流的方法,所以 command pattern 是你的朋友...

    免责声明:代码未经测试!

    public interface Command 
    {
        void invoke();
    }
    
    Map<String, Command> commands = new HashMap<String, Command>();
    commands.put("function1", new Command() 
    {
        public void invoke() { System.out.println("hello world"); }
    });
    
    commands.get("function1").invoke();
    

    【讨论】:

    • Java 确实有闭包,但没有一流的方法。匿名内部类在其封闭范围内关闭(最终)变量。
    • @Nat - 实际上,我从未将匿名类或内部类视为闭包,但我猜它们是。已更新答案以删除该评论。谢谢!
    【解决方案2】:

    有几种方法可以解决这个问题。其中大部分已经发布:

    • Commands - 在映射中保留一堆具有 execute() 或 invoke() 方法的对象;按名称查找命令,然后调用方法。
    • Polymorphism - 比命令更普遍的是,您可以调用任何相关对象集的方法。
    • 终于有了反射 - 您可以使用反射来获取对 java.lang.Method 对象的引用。对于一组已知的类/方法,这工作得相当好,并且一旦加载 Method 对象就没有太多开销。例如,您可以使用它来允许用户在命令行中键入 java 代码,您可以实时执行该命令。

    我个人会使用命令方法。命令与Template Methods 很好地结合在一起,允许您在所有命令对象上强制执行某些模式。示例:

    public abstract class Command {
      public final Object execute(Map<String, Object> args) {
        // do permission checking here or transaction management
        Object retval = doExecute(args);
        // do logging, cleanup, caching, etc here
        return retval;
      }
      // subclasses override this to do the real work
      protected abstract Object doExecute(Map<String, Object> args);
    }
    

    只有当您需要对设计不受控制的类使用这种映射时,我才会诉诸反射,并且为这些类编写命令是不切实际的。例如,您不能通过为每个方法创建命令来在命令外壳中公开 Java API。

    【讨论】:

      【解决方案3】:

      您可以使用 Map 或 Map 等,然后使用 map.get("function1").invoke(...)。但通常使用多态性而不是查找可以更干净地解决这类问题。

      【讨论】:

      • 具体来说,策略模式 (en.wikipedia.org/wiki/Strategy_pattern#Java) 在这里可能会有所帮助(不像 Python 等价物那么短,但是..)。
      • 如何通过多态来做到这一点?需要涉及的功能基于来自客户端的输入。可以展示给我吗?谢谢。
      【解决方案4】:

      多态示例..

      public interface Animal {public void speak();};
      public class Dog implements Animal {public void speak(){System.out.println("treat? treat? treat?");}}
      public class Cat implements Animal {public void speak(){System.out.println("leave me alone");}}
      public class Hamster implements Animal {public void speak(){System.out.println("I run, run, run, but never get anywhere");}}
      
      Map<String,Animal> animals = new HashMap<String,Animal>();
      animals.put("dog",new Dog());
      animals.put("cat",new Cat());
      animals.put("hamster",new Hamster());
      for(Animal animal : animals){animal.speak();}
      

      【讨论】:

        【解决方案5】:

        很遗憾,Java 没有一流的功能,但考虑如下接口:

        public interface F<A, B> {
          public B f(A a);
        }
        

        这将函数类型从A 类型建模为B 类型,作为您可以传递的一等值。你想要的是Map&lt;String, F&lt;A, B&gt;&gt;

        Functional Java 是一个以一流函数为中心的相当完整的库。

        【讨论】:

          【解决方案6】:

          正如在其他问题中提到的,带有匿名内部类的 Map&lt;String,MyCommandType&gt; 是一种冗长的方法。

          一种变体是使用枚举代替匿名内部类。枚举的每个常量都可以实现/覆盖枚举或实现的接口的方法,与匿名内部类技术非常相似,但没有那么混乱。我相信 Effective Java 2nd Ed 处理如何初始化枚举映射。从枚举名称映射只需要调用MyEnumType.valueOf(name)

          【讨论】:

            【解决方案7】:

            正如其他人所说,Java 不支持将函数作为第一级对象。为此,您使用 Functor,它是一个包装函数的类。 Steve Yegge 对此有一个nice rant

            为了帮助您解决这个限制,人们编写了函子库:jgaCommons Functor

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2016-01-27
              • 2011-06-08
              • 1970-01-01
              • 2011-03-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多