8

我们在工作中就在 Java 中使用监听器的最佳实践进行了辩论:监听器逻辑是否应该保留在匿名类中,还是应该在单独的方法中,例如:

button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // code here
    }
});

或者

button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        buttonPressed();
    }
});

private void buttonPressed() {
    // code here
}

就可读性和可维护性而言,推荐的方法是什么?我更喜欢将代码保留在侦听器中,只有在变得太大时,才将其设为内部类。在这里,我假设代码不会在其他任何地方重复。

谢谢你。

4

6 回答 6

4

我自己强加的规则是:

  1. 如果侦听器有 2 个以上的方法,则创建一个命名类。
  2. 如果侦听器跨越 10 行以上,则创建一个命名类。

非常简单,易于遵循并产生或多或少可读的代码。但我不得不承认,我什至从未想过你的例子显示了什么。

于 2011-01-15T19:23:22.340 回答
2

这个问题在这里得到部分回答:

听众有更好的做法吗

我也不喜欢匿名方式,原因有两个:
1)你不能轻易地重用代码,所以一段时间后你可能会发现你有重复的代码 2)我发现它破坏了代码的阅读(其他人不同意。 .. 个人品味)。我想每个人都会同意,如果你做超过 5-10 行匿名内部类不是一个好主意(我会说超过 2 行太多了)。

于 2011-01-15T19:24:40.697 回答
1

在我个人看来,“这取决于”。如果监听器只是被添加到单个组件中,非常简单并且是 GUI 的一个组成部分,那么匿名内部类就可以很好地工作。如果监听器比较复杂,会被添加到多个组件中,会有自己独立的状态,那么单独的独立类会更好。介于两者之间的是私有内部类。HTH。

编辑:我的坏。我在回答一个不同的问题——是否为听众使用单独的独立类。至于是否将匿名内部类代码内联与在方法中,我同意另一张海报,这将取决于侦听器代码的大小和复杂性。

于 2011-01-15T19:24:25.117 回答
1

如果buttonPressed()需要从匿名内部类以外的任何地方访问该方法,请使用方法。否则只需将代码放在actionPerformed().

于 2011-01-15T19:26:09.800 回答
1

以我个人的经验,最好遵循 MVC 模式。这样,就有一个代表模型的单独类,它创建所有相关的动作、动作侦听器等。最好将动作表示为最终类字段,在构造函数中实例化。

例如:

public class Model {
    private final Action buttonAction;
    ...

    public Model(final IController controller) {
       buttonAction = createButtonAction(controller);
       ...
    }

    private Action createButtonAction(final IController controller) {
        Action action = new Action("Action") {
            public void actionPerformed(final ActionEvent e) {
                // do the required action with long running ones on a separate Thread
                controller.run();
            }
        };
        action.set...// other initialisation such as icon etc
        ...
        return action;
    }
    ...

    public Action getButtonAction() {
        return buttonAction;
    }
}

视图也由一个单独的类表示,该类将模型作为其构造函数参数,实际按钮实例化发生在该类中。例如:

public class View extends JPanel {
    public View(final Model model) {
       ...
       JButton button = new JButton(model.getButtonAction();
       ...
    }
}

使用这种方法,将 actionPerformed 的逻辑实现为匿名类的一部分非常方便,因为它几乎没有可重用。所有的逻辑都封装在控制器中,因此动作实际上充当了控制器调用的包装器,用作按钮的模型。

于 2011-01-15T19:27:56.953 回答
0

是的,这在很大程度上取决于您要做什么。我认为匿名内部类由于两个神话而受到了不好的批评。一是不能重用匿名代码。第二,内存泄漏。但是这些都可以通过简单的方法轻松解决。保存对实例的引用。对于共享代码,只需创建对匿名内部类的引用。

Action action = new AbstractAction("Open") {...};
JButton button = new JButton( action );
JMenuItem menuItem = new JMenuItem( action );
panel.getActionMap().put("openFile", action );

现在,您可以跨多个组件重用该操作。对于后面的内存泄漏问题,您可以使用该引用来取消注册它,或者第二个更简单的选项是 WeakListeners。WeakListeners 的优点是在创建后不需要对其进行管理。

至于风格,我发现匿名侦听器非常方便,并且在某些情况下在处理 Swing 中的线程时更易于阅读,因为它将您的代码保持在一种方法中(invokeLater、executeInBackground 等)。当您匿名侦听器委托给一个实例方法时,我认为它将您无法读取侦听器之前发生的事情的代码与一个屏幕中与侦听器关联的逻辑分开。他们往往会分开,而且更难追随。

Something to be aware of is if you use ActionMaps most of the memory leaks will go away associated with keyboard listening. Unfortunately things like focus listeners or listeners that are registered with central systems are still a problem. (Again WeakListeners are great here). And you already have a place to keep the action with every component so no need to create extra instance variables to hold it. If you need to reuse across two components (say in a menu bar and in a control) create a separate class.

于 2011-01-16T01:44:32.720 回答