【问题标题】:Is there a better practice for Listeners?听众有更好的做法吗?
【发布时间】:2009-11-22 18:51:23
【问题描述】:

假设我有一个摇摆 GUI,我想听 MouseEvents。你觉得Listener类应该由谁来负责,应该由谁来负责?实现它的最佳或首选方式是什么?有什么意见吗?我通常是这样去的:

public class MyPanel extends JPanel implements MouseListener{
    private JTable table;
    public void foo(){
         table.addMouseListener(this);
    }
    /* MouseListener */
    //Implement MouseListener here.
}

有没有更好的办法?


编辑:感谢大家的智慧和帮助。我很感激。

【问题讨论】:

  • 我猜添加 JTable 的鼠标侦听器可能并不总是符合您的要求。

标签: java oop listeners


【解决方案1】:

有几种常见的方法来做事件监听器(我能想到的唯一一种我在下面的代码中遗漏的方法是静态内部类)。下面的代码使用 ActionListener,因为它最简单,但您可以将这个想法应用到任何监听器。

请注意,“this”方式(让类实现侦听器)可能会导致大量 if/else 语句。因此,我会说这是最糟糕的方式。我不喜欢“票据交换所”方法有两个原因:

1) 它们很大 2)在方法内部完成工作而不是让每个 if/else 调用一个方法来完成工作是很诱人的(正如你所看到的,这就是我在这里所做的......哎呀 :-)

我也不喜欢匿名方式,原因有两个:

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

这留下了内部和外部的方式。当我编写一个与它正在侦听的 GUI 没有紧密联系的侦听器时,我会使用外部方式。如果侦听器不需要属于类的信息(成员变量/方法)(在本例中为 TestFrame),我会选择外部类。在下面的示例中,我传入了“this”,以便外部侦听器可以访问 GUI……如果我要编写这样的代码,我会将其改为内部类,因为它需要 GUI 中的某些内容。

所以,我的优先顺序是:

  • 内部类(如果可能的话是静态的,但如果你将其设为静态,我会选择外部类)
  • 外部类
  • 匿名内部类(罕见)
  • 让类自己实现(我永远不会这样做。永远不会!)

这是代码

import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;


public class Main
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(
            new Runnable() 
            {
                public void run() 
                {
                    createAndShowGUI();
                }
            });
    }

    private static void createAndShowGUI()
    {
        final TestFrame frame;

        frame = new TestFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBounds(new Rectangle(10, 10, 300, 300));
        frame.init();
        frame.setVisible(true);
    }
}

class TestFrame
    extends    JFrame
    implements ActionListener
{
    private final JButton aBtn;
    private final JButton bBtn;

    public TestFrame()
    {
        super("Test");

        aBtn = new JButton("A");
        bBtn = new JButton("B");
    }

    public void init()
    {
        setLayout(new FlowLayout());
        add(aBtn);
        add(bBtn);

        // the class, since it implements ActionListener
        aBtn.addActionListener(this);
        bBtn.addActionListener(this);

        // outer classes
        aBtn.addActionListener(new OuterAListener(this));
        bBtn.addActionListener(new OuterBListener(this));

        // inner class
        aBtn.addActionListener(new InnerAListener());
        bBtn.addActionListener(new InnerBListener());

        // anonymous classes
        aBtn.addActionListener(
            new ActionListener()
            {
                public void actionPerformed(final ActionEvent e)
                {
                    System.out.println ("Hi from Anonymous A");
                }
            });

        bBtn.addActionListener(
            new ActionListener()
            {
                public void actionPerformed(final ActionEvent e)
                {
                    System.out.println ("Hi from Anonymous B");
                }
            });
    }

    public void actionPerformed(final ActionEvent evt)
    {
        final Object source;

        source = evt.getSource();

        if(source == aBtn)
        {
            System.out.println ("Hi from this A");
        }
        else if (source == bBtn)
        {
            System.out.println ("Hi from this B");
        }
        else
        {
            // ???
        }
    }

    private class InnerAListener
        implements ActionListener
    {
        public void actionPerformed(final ActionEvent e)
        {
            System.out.println ("Hi from Inner A");
        }
    }

    private class InnerBListener
        implements ActionListener
    {
        public void actionPerformed(final ActionEvent e)
        {
            System.out.println ("Hi from Inner B");
        }
    }
}

class OuterAListener
    implements ActionListener
{
    private final TestFrame frame;

    public OuterAListener(final TestFrame f)
    {
        frame = f;
    }

    public void actionPerformed(final ActionEvent e)
    {
        System.out.println ("Hi from Outer A");
    }
}

class OuterBListener
    implements ActionListener
{
    private final TestFrame frame;

    public OuterBListener(final TestFrame f)
    {
        frame = f;
    }

    public void actionPerformed(final ActionEvent e)
    {
        System.out.println ("Hi from Outer B");
    }
}

【讨论】:

    【解决方案2】:

    我建议将侦听器放在自己的类中,使其可重用,并明确分离关注点

    【讨论】:

    • (另外,不要扩展JPanel(除非你是认真的)。)
    【解决方案3】:

    查看 Java 的 Swing 代码。这确实是看到良好标准的最佳场所。

    在你的情况下,我会有类似的东西:

    public class MyPanel extends JTable {
    
        public void foo() {
             addMouseListener(new MouseHandler() );
        }
    
        private class MouseHandler implements MouseListener {
           ...
        }
    }
    

    这样你就有了明确的功能分离。当您的主类开始实现 15 个不同的接口时,您的代码将变得完全无法维护。

    【讨论】:

      【解决方案4】:

      匿名类主要用于监听器。如果您知道您将只注册一次特定的侦听器并且它很短,那么您可以使用匿名类。

      【讨论】:

        【解决方案5】:

        就个人而言,我喜欢将我的 GUI 与控制器分开。所以我建议在Controller类中实现监听器(每个功能GUI都有自己的)并在那里工作,即使它需要使用if...elseswich...case

        【讨论】:

          猜你喜欢
          • 2019-10-17
          • 1970-01-01
          • 2023-01-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-12-15
          • 1970-01-01
          • 2017-03-24
          相关资源
          最近更新 更多