在Java中为GUI和ActionListener组织代码

4
我刚开始学习Java,想知道如何在我的项目中实现ActionListener代码。我知道内部类和实现ActionListener接口的方法,但这样做会使代码看起来比应该更混乱。
我是否需要编写另一个实现ActionListener并扩展GUI的类ActionCode?您建议采取什么方法以及为什么?
对此,您的最佳实践建议是什么,我可以在哪里找到这些指南?(JavaDoc似乎解释了ActionListeners的基本实现,但似乎没有任何模型来组织大型/中型项目)。

使用提供方法默认实现的适配器,然后在需要不同行为的地方提供覆盖。 - jww
2
可能是在Java中实现接口并重写方法?的重复问题。 - jww
3个回答

3
在我看来,并没有“最佳”方法。即使是sun/oracle教程中的代码示例也使用不同的方式来实现监听器。
从我的经验来看,一个好的方法是:
- 使用匿名实现:人们知道这个模式并且很快就能认出它。如果有一种常见的做事方式,帮助读者理解代码。 - 有一个专门处理监听器的方法(例如private void addListeners()):同样,这可以帮助每个人认识到它并知道在哪里搜索所有逻辑。 - 保持监听器简单。这意味着少于5-10行代码。如果需要更复杂的逻辑,请调用一个方法。 - 保持监听器数量较少。如果需要>50个监听器,则可能需要重构视图。如果需要超过10个,则可以考虑重构。
除了这些通用点外,总有例外。比如,如果有许多具有相同行为的组件,则可以编写一个带有switch/case的通用监听器。(典型示例:计算器按钮或菜单按钮)。 或者,如果多个组件具有相同的逻辑,则可以使用特定的类。 等等。
还要提一下,因为sun/oracle教程中有一些示例:尽量避免使用视图类本身实现监听器接口。如果只有一个监听器,这可能没问题,但是对于来自多个源的多个事件具有不同行为的情况,大多数情况下都很糟糕。

1

代码风格可能是个人口味的问题,但现代文献表明它不仅仅是如此。让《代码整洁之道》中的“类”章节为您指引方向。

类应该小!
类的第一条规则是它们应该很小。类的第二条规则是它们应该比那还要小。不,我们不会重复“函数”章节中完全相同的文本。但是与函数一样,设计类时,更小是主要规则。与函数一样,我们的直接问题总是“多小?”对于函数,我们通过计算物理行数来衡量大小。对于类,我们使用不同的度量标准。我们计算职责...
单一职责原则(SRP)规定一个类或模块应该有一个且仅有一个变化的原因。这个原则为我们提供了职责的定义和类大小的指导方针。类应该有一个职责-一个变化的原因...
问题在于我们中的许多人认为一旦程序工作就完成了。我们没有转向组织和清洁的另一个关注点。我们继续前进到下一个问题,而不是回去将过度填充的类分解成具有单一职责的解耦单元。同时,许多开发人员担心大量的小型单一用途类会使理解更大的图像更加困难。他们担心必须从一个类导航到另一个类,以便弄清楚如何完成更大的工作。然而,具有许多小类的系统与具有少数大类的系统一样多。在具有少数大类的系统中,学习的内容同样多。所以问题是:您想将工具组织成具有许多小抽屉的工具箱,每个抽屉都包含定义明确且标记良好的组件?还是你只想要几个抽屉,把所有东西都扔进去?
每个规模较大的系统都将包含大量的逻辑和复杂性。管理这种复杂性的主要目标是将其组织起来,以便开发人员知道在哪里查找事物,并且在任何给定时间只需要理解直接受影响的复杂性。相比之下,具有更大、多用途类的系统总是通过要求我们浏览许多我们现在不需要了解的内容来妨碍我们。为了强调前面的观点,重新陈述一下:我们希望我们的系统由许多小类组成,而不是少数大类。每个小类封装一个单一职责,有一个变化的原因,并与其他几个类合作以实现所需的系统行为。

因此,基于这些启发式规则,嵌套类违反了SRP原则。它们几乎永远不应该出现。相反,您的GUI类应包含它们注册的ActionListeners的实例成员。将监听器放在单独的*.listener包中。使用接口使它们可以替换(策略模式),在任何被认为有效的地方都可以使用。


0

Java和Swing鼓励使用许多像Listeners和Actions这样的小对象。这是很多模板代码,但这就是Java的方式。与其对抗,没有太多好处。

创建匿名监听器是相当轻松的:

JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        ok();
    }
});

然而,您经常需要重复使用操作,例如将相同的操作分配给菜单和按钮。您可以将它们作为内部类放置在主应用程序窗口中:

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;


public class MainWindow extends JFrame {

    ZapAction zapAction;

    public MainWindow() {

        setSize(new Dimension(200,200));

        zapAction = new ZapAction();

        JMenuBar menuBar = new JMenuBar();
        JMenu menu = new JMenu("Foo");
        menu.add(new JMenuItem(zapAction));
        menuBar.add(menu);
        setJMenuBar(menuBar);

        JButton zapButton = new JButton(zapAction);

        add(zapButton);
    }

    public void zap() {
        // do some zapping
        System.out.println("Zap!");
        // maybe we're all done zapping?
        zapAction.setEnabled(isZappingPossible());
    }

    public boolean isZappingPossible() {
        // determine if there's zapping to be done
        return Math.random() < 0.9;
    }

    class ZapAction extends AbstractAction {
        public ZapAction() {
            super("Zap");
            putValue(AbstractAction.SHORT_DESCRIPTION, "Zap something");
            putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
                KeyEvent.VK_Z, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
            putValue(AbstractAction.SMALL_ICON, 
                new ImageIcon(MainWindow.class.getResource("/icons/zap.png")));
            setEnabled(true);
        }
        public void actionPerformed(ActionEvent e) {
            zap();
        }
    }
}

public class Zap {
    public static void main(String[] args) {
        MainWindow mainWindow = new MainWindow();
        mainWindow.setVisible(true);
    }
}

在这里,ZapAction 是包私有的可见性。我把所有的UI代码放在它自己的包中(比如说 org.myorg.myproject.ui)。所以,所有的UI对象都可以访问这些操作。

在一个复杂的Swing应用程序中,我甚至创建了一个UI外观层,它是一个很好的地方来放置动作和所有将它们连接到各种控件的代码。它还提供了一个方便的地方让外部代码与UI交互,将UI代码与核心应用程序代码隔离开来。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接