问题 GUI中监听器的嵌套类的优点


对于体积适中的项目,我被告知当你有扩展JPanels的类时,最好的做法是使用嵌套类来实现监听器。例如,我可以有一个扩展JPanel的类FactoryScreen,并有一个嵌套类FactoryScreenBrain,它实现了所有必要的监听器。

我从来没有能够以这种方式为我的类封装特定的好处或缺点得到一个很好的解释,直到现在总是只有扩展JPanel和实现监听器的类。有人能为我提供一些指导吗?


2747
2018-02-22 23:08


起源

不必要地扩展一个 JPanel (要么 JFrame 要么 Thread)不是最佳做法。但是,GUI编程和良好实践并不倾向于满足 - Tom Hawtin - tackline


答案:


为听众设置内部课程可以使所有听众的目的非常清晰。如果以更多编码为代价进行检查,它有时也可以避免许多。

如果你有一个小组

public class MyPanel extends JPanel implements ActionListener
...
    button1.addActionListener(this);
    button2.addActionListener(this);
    checkbox1.addActionListener(this);
    timer3.addActionListener(this);

    public void actionPerformed(ActionEvent e)
    {
        if(e.getSource() == button1)
        else...
        ... //potentially many elses
    }

很难确切地看到你的actionPerformed中发生了什么,因为它一次处理了很多不同的事件。有一个小组:

public class MyPanel extends JPanel
...
    button1.addActionListener(new ButtonListener());
    button2.addActionListener(new ButtonListener());
    checkbox1.addActionListener(new CheckBoxListener());
    timer3.addActionListener(new TimerListener());

    private class TimerListener implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            //do stuff related only to timers
        }
    }

现在,如果您的计时器有问题,您可以轻松识别出有问题的班级。

更重要的是,在大规模上,它使您的代码更具可读性。如果其他人想要在这个类上工作并且他们需要使用计时器修复事件处理,他们不必搜索你的ifs以找到具有计时器逻辑的部分。


8
2018-02-22 23:41





我认为任何东西都比让一个类扩展一个Swing组件并实现一个监听器更好,因为它给了类太多不同的职责,并为创建可怕的交换板监听器设置了一个。我尝试使用匿名内部侦听器从单独的控件类调用方法。这样我就分出了责任,可以更容易地孤立地测试每个班级的行为。

顺便问一下好问题。


6
2018-02-22 23:17



对。这是关注点的分离,这是一个巨大的胜利。嵌套(或匿名)内部类只有一个作业要做。使跟踪整个行为变得非常容易。例如,如果你有一个面板,其中有几十个对象调用一个actionPerformed方法,那么它会使该方法更大,更难理解或维护。例如,如果您出于某种目的更改该方法,则会冒着意外影响该方法处理的其他职责的风险。 - Kaffiene
感谢您的评论,也可能是投票。如果是你,你必须把我推到3000以上。小费! :) - Hovercraft Full Of Eels


如果扩展组件并实现一个或多个侦听器,则很容易在构造函数中添加侦听器。这可能会暴露对未完全构造的对象的引用 - 有时称为 逃脱了这一点。专门从事EDT工作可以降低风险;但是一个匿名的内部类可以进一步减少它。反思或问题 间接曝光 依然存在。


2
2018-02-23 02:11



我不确定使用匿名内部类是否摆脱了问题。在页面后面 ibm.com/developerworks/java/library/j-jtp0618.html#3 描述了如果子类依赖于事件,匿名内部类仍可能如何经历竞争条件。我能想到的真正避免这种情况的唯一方法可能是让你的GUI类最终(这在某些情况下肯定是可行的)但链接并没有详细说明解决这个问题的其他方法...... - donnyton
好点子;它不是灵丹妙药。正如约书亚布洛赫所说,“设计和文件的继承,或者禁止它。” - trashgod
我想理解投票结果,所以我可以澄清答案。 - trashgod