【问题标题】:Organize Code for GUI and ActionListener in Java [duplicate]用Java组织GUI和ActionListener的代码[重复]
【发布时间】:2012-12-18 23:54:54
【问题描述】:

我是 Java 新手,想知道如何在我的项目中实现 ActionListener 代码。我知道内部类和ActionListener 接口的实现,但是走这条路会使代码看起来比它应该的更混乱。

我是否会编写另一个类 ActionCode 来实现 ActionListener 并扩展 GUI,或者您会建议哪条路以及为什么?

您对此有什么最佳实践建议,我在哪里可以找到这些指南? (JavaDoc 似乎解释了ActionListeners 的基本实现,但似乎没有任何模型如何组织大/中型项目。

【问题讨论】:

标签: java swing user-interface actionlistener


【解决方案1】:

在我看来,没有“最好”的方法。甚至 sun/oracle 教程中的代码示例也使用不同的方式来实现侦听器。

根据我的经验,一个好的方法是:

  • 使用匿名实现:人们知道这种模式并且会很快认出它。如果有通用的做事方式,它可以帮助读者理解代码
  • 有一个特殊的方法,它只处理监听器(例如private void addListeners()):同样,这有助于每个人识别它并知道在哪里搜索所有逻辑
  • 让听众保持简单。这意味着少于 5-10 行代码。如果您需要更复杂的逻辑,请调用方法。
  • 尽量减少听众数量。如果您需要 > 50 个侦听器,您可能应该重构您的视图。如果需要超过 10 个,可以考虑重构。

除了这些一般要点之外,总会有例外。就像你有很多具有相同行为的组件一样,你可以编写一个带有 switch/case 的通用侦听器。 (典型示例:计算器按钮或菜单按钮)。
或者,如果您对多个组件有相同的逻辑,则可以使用特定的类。
以此类推。

顺便提一下,因为 sun/oracle 教程中有一些示例: 尽量避免使用视图类本身实现侦听器接口。如果您只有一个侦听器,这可能没问题,但大多数情况下,对于来自具有不同行为的多个来源的多个事件来说,这很糟糕。

【讨论】:

    【解决方案2】:

    代码风格可能是个人品味的问题,但现代文献表明它不止于此。让Clean Code 中的 Classes 章节为您指明方向。

    班级应该很小!

    类的第一条规则是它们应该很小。第二条规则 的类是它们应该比那个小。没有,我们没有 将重复功能章节中完全相同的文本。但是作为 对于功能,较小是设计时的主要规则 类。与函数一样,我们的直接问题始终是“如何 小的?”对于函数,我们通过计算物理线来测量大小。 对于类,我们使用不同的度量。我们计算责任...

    单一职责原则 (SRP) 指出,一个类或 模块应该有一个,也只有一个,改变的理由。这个原则 给了我们责任的定义和指导方针 班级规模。类应该有一个责任——一个理由 改变...

    问题是我们中的太多人认为一旦完成 程序有效。我们未能切换到组织的其他关注点 和清洁度。我们继续下一个问题而不是返回 并将过度填充的类分解为具有单个的解耦单元 责任。同时,许多开发人员担心 小型的、单一目的的类的数量使得它更难 了解大局。他们担心他们必须 从一个班级导航到另一个班级,以便弄清楚更大的一块 的工作得到完成。然而,一个有很多小类的系统 没有比具有几个大类的系统更多的活动部件。 与几个大班在系统中学习一样多。所以 问题是:您是否希望将您的工具组织到工具箱中 许多小抽屉,每个抽屉都包含明确定义和标签 组件?或者你想要几个你把所有东西都扔掉的抽屉 进入?

    每一个相当大的系统都会包含大量的逻辑和 复杂。管理这种复杂性的主要目标是 组织它,以便开发人员知道在哪里寻找东西和 只需要了解任何给定的直接影响的复杂性 相比之下,具有更大、多用途类的系统总是 通过坚持我们涉足许多我们不需要的事情来阻碍我们 现在就知道。重申前面的重点:我们想要 我们的系统将由许多小类组成,而不是几个大类 那些。每个小类都封装了一个职责,有一个 改变的唯一理由,并与其他一些人合作以实现 所需的系统行为。

    因此,基于这些启发式方法,嵌套类打破了 SRP。它们几乎不应该发生。相反,让您的 GUI 类包含它们注册的 ActionListener 的实例成员。将侦听器保存在单独的 *.listener 包中。在认为有效的地方使用接口使它们可替换(策略模式)。

    【讨论】:

      【解决方案3】:

      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 代码与核心应用程序代码隔离。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-13
        • 1970-01-01
        • 2015-03-17
        • 1970-01-01
        • 2013-08-25
        • 2012-02-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多