好的,我有一个包含多个Menu和MenuItem的类(我们称之为:MenuBarClass)。 我想给每个MenuItem分配一个actionlistener,但是......而不是做类似的事情:
menuitem_1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {} });
menuitem_2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {} });
menuitem_3.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {} });
// ...
menuitem_N.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {} });
我认为我的代码更具有可持续性......更重要的是......我不会在一个巨大的ActionListener类中出现很多“if”,如:
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(menuitem_1)) {
//do stuff..
} else if (e.getSource().equals(menuitem_2)) {
//do stuff..
} else ...
}
如果有可能,我该怎么做? 有人可以帮忙吗?
答案 0 :(得分:2)
您可以使用reflection API来减少详细程度,以创建实用程序方法:
package demo;
import java.awt.event.*;
import java.lang.reflect.*;
public class ListenerProxies {
private static final Class<?>[] INTERFACES = { ActionListener.class };
public static ActionListener actionListener(final Object target,
String method) {
final Method proxied = method(target, method);
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
ActionEvent event = (ActionEvent) args[0];
return proxied.invoke(target, event);
}
};
return (ActionListener) Proxy.newProxyInstance(target.getClass()
.getClassLoader(), INTERFACES, handler);
}
private static Method method(Object target, String method) {
try {
return target.getClass().getMethod(method, ActionEvent.class);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(e);
} catch (SecurityException e) {
throw new IllegalStateException(e);
}
}
}
这可以像这样使用:
package demo;
import static demo.ListenerProxies.actionListener;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class Demo {
public static void main(String[] args) {
Demo test = new Demo();
JButton hello = new JButton("Say Hello");
hello.addActionListener(actionListener(test, "sayHello"));
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(hello);
frame.pack();
frame.setVisible(true);
}
public void sayHello(ActionEvent event) {
System.out.println("Hello");
}
}
缺点是缺少编译时检查sayHello(ActionEvent)
方法。
性能成本可以忽略不计。
答案 1 :(得分:1)
实际上,这些ActionListener
对象是命令设计模式的命令对象。您可以创建自定义子类而不是匿名子类,并获得更多优点。
现在,如果困扰你的是你如何用命令对象连接动作监听器,我会用反射来做这样的事情:
@MenuAction
的自定义注释,它可以使用正确命令对象的类。如果您认为合适,您可以创建一个框架并在多个项目中使用这种通用方法,但这比简单地用手工正确的ActionListener
实现几个菜单项连接要多得多
答案 2 :(得分:1)
如果你想要做的事情对于每个菜单项是相似的,你可以创建一个实现ActionListener
的类,它接受构造函数参数。例如,如果每个菜单项都应打开JFrame
,您可以执行以下操作:
public class OpenFrameAction implements ActionListener
{
private final JFrame frame;
public OpenFrameAction(final JFrame frameToOpen)
{
this.frame = frameToOpen;
}
public void actionPerformed(ActionEvent e)
{
this.frame.setVisible(true);
}
}
然后为每个菜单项:
menuitem_1.addActionListener(new OpenFrameAction(myFrameForMenuItem1));
答案 3 :(得分:0)
扩展siegi的答案。如果要执行的动作有共同之处(跳下悬崖,做探戈,喝一杯咖啡),你真的只想为每个项目添加单独的听众。如果是这种情况,您不能指望Java为您执行任何可维护性魔术。
更常见的情况是这些行动确实有共同之处(做探戈,做狐步舞等)。如果是这种情况,您可以按照siegi的建议或将听众附加到菜单(而不是项目)。该事件应该告诉您选择了哪个项目,您可以在监听器中使用它:
// something like this
actionPerformed(ActionEvent e)
{
this.doDance(e.getSource().getSelectedValue());
}