将函数作为字符串传递的正确方法

问题描述:

请允许我解释我正在尝试做什么 - 我认为标题可以粗略地解释它,但我不太确定我是否正在处理事情如果我错了,请纠正我的错误!将函数作为字符串传递的正确方法

我使用LayeredPane创建了自定义对话框。基本上jPanel显示在POPUP_LAYER上,因此出现在主要内容的顶部。此面板包含一个简单的'label-textbox-okay-cancel'控件组。我将这称为'对话框面板'。

我是什么要做: 当单击主窗口(包含在LayeredPane内)上的按钮时,对话框面板将出现,并允许用户输入一些文字,然后点击确定或取消。这很简单,但我希望此代码可以重复使用,这意味着主窗口上的其他按钮将调用相同的对话框面板,但标签中的文本不同。

这当然要求我包含某种回调函数,以便Dialog Panel上的okay按钮将根据调用它的按钮来运行正确的代码。

我目前的尝试是存储一个字符串,其中将包含当用户单击对话框面板上的OK按钮时应运行的功能的名称。我试图检索这个字符串并将其转换为函数名称,到目前为止,我已经找到许多对“反射”的引用,其中许多提示它不是一个好主意。

在我一直无法得到任何示例代码的工作,因为我不明白什么是“OBJ”是在下面的代码,但无法调用的方法无论如何:

method = obj.getClass().getMethod(myCallbackString); 

我的问题是:

首先,我是否正在以正确的方式进行?我更愿意接受建议,但请尽量保持简单,因为我真的刚刚开始!

其次,上面显示的代码中的'obj'是什么?我真的很想知道,即使这不是我应该做的事情!

我的其他想法包括:我的Dialog Panel是否应该在它自己的类中,如果是,再次如何传递回调函数?

任何帮助或建议将受到感谢。

顺便说一句:回答“为什么不使用正常对话框?”的问题。我只能说我目前正在试验,而我只是想看看我能否做到这一点!

MVK

+1

'getMethod'只有在方法公开的情况下才能使用。如果它是私人的,你需要使用'getDeclaredMethod'。获取方法后,需要调用它:'method.invoke(obj,anyParameters)',其中obj是要调用该方法的对象。 – 2012-07-08 13:03:23

+1

我认为使用'switch'语句选择要调用的方法可能更明智。 – 2012-07-08 13:09:25

obj名字你想调用其方法的对象,你的情况,也许可以与this更换(或删除它完全,因为this是暗示):

private void callByName(String name) { 
    try { getClass().getMethod(name).invoke(this); } 
    catch (RuntimeException e) { throw e; } 
    catch (Exception e) { throw new RuntimeException(e); } 
} 

对于这个工作你需要用适当的名称声明公共的无参数方法。

+0

非常感谢Marko,当我测试它时,这段代码就工作了 - 我会接受这个答案,因为它实际上回答了这个问题,但我已经注意到在使用这种方法时存在潜在的问题。 – MaxVK 2012-07-08 14:26:30

+0

是的,存在问题,但是由于您正在学习,尝试它并查看您是否自己解决问题并不是一种罪过。 – 2012-07-08 14:27:39

我还没有与JPanel的工作,但我的理解表格,答案似乎很简单。为什么不在接口上工作并传递该接口的不同实现,而不是传递方法名称?

通过Java程序传递回调函数的常用方式是通过传递实现特定回调函数的接口实例。匿名实现界面是典型的,但不是必需的。

例如,这里是一个接口:

interface MyCallback { 
    void performCallback(); 
} 

这里是你定义你的对话框的方法,需要一个回调的方式:

void openWithCallback(MyCallback cb) { 
    // Do something useful... 
    ... 
    // Perform the callback 
    cb.performCallback(); 
} 

这里是你调用该方法的方式:

public void OpenDialog() { 
    myDialog.openWithCallback(new MyCallback() { 
     public void performCallback() { 
      System.out.println("Inside callback..."); 
     } 
    }); 
} 
+0

非常感谢dasblinkenlight,我现在已经采用了另一种方法,但我也会在某些时候尝试。 – MaxVK 2012-07-08 14:28:25

  1. 我认为你的想法是Val id,尽管它有一个主要缺点:在代码中将方法名称存储为简单的字符串,因此编译器无法检查它们的有效性。因此,如果更改方法的名称,则必须手动确保更新了引用该方法的所有字符串。 这通常意味着'反射是一个坏主意'。
  2. obj在您的代码中是您要调用方法的对象。作为一个简单的例子,someInteger.toString();的等值反射将是someInteger.getClass().getMethod("toString").invoke();

在一个更通用的音符,一旦你熟悉的Java,你可能还检查了像斯卡拉,其中功能是有规则物体的功能性语言,你想让你的情况可能与完整的编译器检查来实现。

+0

感谢tehlexx,注意到您对检查有效性的担忧,尽管在这种情况下它并不是一个真正的问题。我会在某个时候看看Scala,谢谢你的建议。 – MaxVK 2012-07-08 14:21:50

+0

伟大的,快乐的学习! – tehlexx 2012-07-09 08:34:58

我认为你正在使这种的方式比它必须更复杂。你说你想要这个:

This is all easy enough, but I would like this code to be re-usable, which means 
that other buttons on the main window will invoke the same Dialog Panel, but with 
different text in the label. 

根据定义,DialogBox是可重用的。为什么不单单按钮点击侦听器在单击时将适当的文本传递给对话框,以便显示正确的信息?

如果需要具体的行动取决于调用该对话框上的按钮,点击后发生,你可能要考虑:

  1. 创建的自定义对话框扩展,包括逻辑,知道做基于什么谁打电话给他。然后,当一个按钮调用自定义对话框时,它会传递一个参数让对象在关闭对话框后知道它想做什么。

  2. 看看使用抽象工厂模式。

是的,你可以通过反射来做到这一点。是的,这将是一个非常糟糕的主意,原因是多方面的,其他人在其他的答案已经讨论过,尤其是如果这是生产代码(尽管你似乎表明它是一个实验。)

如果你真的只是想看看如何用反思来工作,你可能想要阅读这个话题。我发现this是更好的教程之一。

+0

感谢Roddy,是的,它现在是一个实验,尽管我很可能会尝试几种不同的方法来获得相同的结果,包括您建立自定义DialogBox的建议,谢谢。 – MaxVK 2012-07-08 14:20:39