为给定值定义回调函数

时间:2010-09-13 16:38:53

标签: java android refactoring callback

在Java中,是否可以将某个对象(即String)与要调用的函数关联起来?

我有两个相似的菜单,两个都有一个onClickListener,代码如下:

if (item.id==0) {
 doSomeFunction(argument);
}
else if (item.id==1) {
 doSomeOtherFunction();
}
else if (item.id==2) {
 doStuff(arg2);
}
else {

}

我想要一个对象(即Hashtable),它允许我定义“item.id” - >之间的关联。 “要执行的代码”。

示例:

0 -> doSomeFunction(argument);
1 -> doSomeOtherFunction();
2 -> doStuff(arg2);

因此,我可以跳过这些条件并只执行为给定item.id存储的函数的函数调用。

例如,使用Lisp,我可以将item.id与函数关联,然后使用Lisp的“funcall”来调用该函数。

在Java中有没有一种标准的方法可以做这样的事情?

是否有其他解决方案可以跳过条件?

请注意,被叫函数可能需要接收参数。

感谢。

4 个答案:

答案 0 :(得分:3)

由于您的函数看起来不需要返回任何值,因此您可以将每个ID键与调用所需方法的Runnable对象相关联。例如:

Map<Integer, Runnable> map = ...;
map.put(0, new Runnable() {
  public void run() {
    doSomeFunction();
  }
});

map.get(0).run();

如果您需要方法能够返回值,则可以使用Callable而不是Runnable。您也可以创建自己的类似界面,并在需要时使用它。

目前在Java中,必须使用单个抽象方法(例如Runnable)对类的实例进行此类操作。 Java 7或8(取决于他们决定如何继续)将添加lambda表达式和方法引用,我认为这是你真正想要的。方法参考将允许您执行类似这样的操作(使用Map<Integer, Runnable>,如上所述)。

map.put(0, Foo#doSomeFunction());

修改

您的更新表明其中一些方法需要传递参数。但是,你似乎要求两件不同的事情。在您声明映射的示例中

0 -> doSomeFunction(argument);
1 -> doSomeOtherFunction();
2 -> doStuff(arg2);

指定了参数,表明它们是您声明映射时可用的值,或者它们是类中的字段或某些字段。在任何一种情况下,您都可以在创建Runnable

时声明它们
 new Runnable() {
   public void run() {
     doSomeFunction(argument);
   }
 }

此处,argument要么必须是字段,要么声明为final

另一方面,如果在创建映射时没有对参数的引用,则必须创建一个所有方法调用可以共享的一致接口。例如,可以用于您的示例的最不常见的接口将是声明两个参数和void返回的接口:

public interface CustomRunnable<T,G> {
  public void run(T arg1, G arg2);
}

然后你可以:

map.put(0, new CustomRunnable<Foo,Bar>() {
  public void run(Foo arg1, Bar arg2) {
    doSomeFunction(arg1);
  }
});
map.put(1, new CustomRunnable<Foo,Bar>() {
  public void run(Foo arg1, Bar arg2) {
    doSomeOtherFunction();
  }
});
map.put(2, new CustomRunnable<Foo,Bar>() {
  public void run(Foo arg1, Bar arg2) {
    doStuff(arg2);
  }
});

每个CustomRunnable仅使用它需要的参数(如果有的话)。然后你可以这样打电话:

map.get(item.id).run(argument, arg2);

显然,这变得非常难看,但在这种情况下,这几乎就是你必须要做的事情。

答案 1 :(得分:1)

是的,有几种方法可以做到这一点。一个例子是匿名实现接口并将其存储在HashMap中,如下所示:

public class MyListeningClass
{
    ...

    public interface MyEventHandler
    {
        public void handle(String myParam);
    }

    private HashMap<ItemType, MyEventHandler>  eventHandlers= new HashMap<ItemType, MyEventHandler>();

    initItems()
    {
        //do for each item
        eventHandlers.put(item1, new MyEventHandler(){public void handle(String myParam){
                   //do whatever I want to
                 }});
    }

    myListeningMethod(ItemType item)
    {
        eventHandlers.get(item).handle("a parameter");
    }
}

答案 2 :(得分:1)

通常要做的是在每个菜单项上添加一个不同的动作侦听器(命令),实现为一个简短的匿名内部类。不幸的是,语法目前很冗长,它无助于启动时间,但它仍然是最好的方法。

您没有说出您正在使用的库。 onClickListener不是Swing,但如果您使用的是Swing,则需要JMenuItem.addActionListener

答案 3 :(得分:0)

Java Swing的回答方式是Action类。基本上它遵循命令模式......