【发布时间】:2009-06-01 11:48:37
【问题描述】:
在 python 中,如果我想根据输入调用一些函数,我可以这样做:
lookup = {'function1':function1, 'function2':function2, 'function3':function3}
lookup[input]()
也就是说我有一个映射到函数的函数名字典,并通过字典查找调用该函数。
如何在java中做到这一点?
【问题讨论】:
在 python 中,如果我想根据输入调用一些函数,我可以这样做:
lookup = {'function1':function1, 'function2':function2, 'function3':function3}
lookup[input]()
也就是说我有一个映射到函数的函数名字典,并通过字典查找调用该函数。
如何在java中做到这一点?
【问题讨论】:
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();
【讨论】:
有几种方法可以解决这个问题。其中大部分已经发布:
我个人会使用命令方法。命令与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。
【讨论】:
您可以使用 Map
【讨论】:
多态示例..
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();}
【讨论】:
很遗憾,Java 没有一流的功能,但考虑如下接口:
public interface F<A, B> {
public B f(A a);
}
这将函数类型从A 类型建模为B 类型,作为您可以传递的一等值。你想要的是Map<String, F<A, B>>。
Functional Java 是一个以一流函数为中心的相当完整的库。
【讨论】:
正如在其他问题中提到的,带有匿名内部类的 Map<String,MyCommandType> 是一种冗长的方法。
一种变体是使用枚举代替匿名内部类。枚举的每个常量都可以实现/覆盖枚举或实现的接口的方法,与匿名内部类技术非常相似,但没有那么混乱。我相信 Effective Java 2nd Ed 处理如何初始化枚举映射。从枚举名称映射只需要调用MyEnumType.valueOf(name)。
【讨论】:
正如其他人所说,Java 不支持将函数作为第一级对象。为此,您使用 Functor,它是一个包装函数的类。 Steve Yegge 对此有一个nice rant。
为了帮助您解决这个限制,人们编写了函子库:jga、Commons Functor
【讨论】: