ActionListener样式 - 好的或坏的

时间:2012-11-09 23:43:01

标签: java swing coding-style inner-classes anonymous-class

我有一个简单的GUI,其中包含:

  • 一个按钮。
  • 两个单选按钮

现在我想听一下这些按钮。我做的是这样的:

public class TestApp implements ActionListener {

    private JFrame frame;
    private JButton btn;
    private JRadioButton rdb1;
    private JRadioButton rdb2; 

    public static void main(String[] args) { /*....*/ }

    private void initialize() {
       //Each time I add a button, I add it to the listener:
       btn = new JButton("Button");
       btn.addActionListener(this);
       //..
       rdb1 = new JRadioButton("Value1");
       rdb1.addActionListener(this);
       //And so on...
    }

    //The ActionEvents  
    public void actionPerformed(ActionEvent e) {
       if(e.getSource()==btn)
       //...
       if(e.getSource()==rdb1)
       //...        
    }
}

现在我想知道这是否是一种好/坏的风格?

5 个答案:

答案 0 :(得分:5)

除非听众是一个很长的方法,否则我个人更喜欢匿名类模式:

        final JButton btn = new JButton("Button");
        final JRadioButton rdb1 = new JRadioButton("Value1");
        final ActionListener listener = new ActionListener() {
            @Override
            public void actionPerformed(final ActionEvent e) {
                if (e.getSource() == btn) {
                    //...
                } else if (e.getSource() == rdb1) {
                    //...        
                }
            }
        };
        btn.addActionListener(listener);
        rdb1.addActionListener(listener);

甚至更好:

    btn.addActionListener(new ActionListener (){
         public void actionPerformed(ActionEvent e) {      
             // btn handling code
             }
    });
    rdb1.addActionListener(new ActionListener (){
         public void actionPerformed(ActionEvent e) {      
             // rdb1 handling code
             }
    });

您正在使用的模式允许其他类将类TestApp设置为由其他类设置为侦听器 - 除非这是预期的,否则这不是一个好习惯。

答案 1 :(得分:4)

很多事情都归结为动作监听器试图做的事情的复杂性。如果你想要小的,单次使用的动作,那么匿名类是合适的。

使用这种侦听器的主要好处是它将准确地隔离动作正在做什么以及它正在做什么。当听众包含更多,比如10行或更多行时,会出现这种缺点,因为它开始变得难以阅读并且知道听众实际结束的位置。

在这种情况下,像内部类这样的东西可能更合适。它有一个匿名类的好处(与使用它的类相关联),但更容易阅读。

如果你想要可重复使用的动作(想想开放,新的,保存等),那么你最好使用Action API,它提供自我配置以及自包含的动作监听器

恕我直言

答案 2 :(得分:3)

更多面向对象的方法是创建一个匿名类来实现每个侦听器。

仅创建一个用于打开事件源组件的侦听器不是非常易读,而且,当侦听器数量增加时,它会变得容易出错。您可以轻松地忘记处理switch块中的所有可能的事件源(或if-else块链),这将导致运行时异常无声错误行为(对于那种情况不会发生任何事情)。

为每个组件添加单个侦听器将为您提供编译时检查,您不会忘记处理所有组件。

public class TestApp {

    // you can initialize fields inline to make thing shorter and safer
    private JButton btn = new JButton("Button");
    private JRadioButton rdb1 = new JRadioButton("Value1");

    private void initialize() {
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // something
            }
        });
        rdb1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // something else
            }
        });
    }
}

因为匿名类语法非常详细,所以可以通过将侦听器移动到私有字段来缩短initialize方法的代码。

public class TestApp {

    private JButton btn = new JButton("Button");
    private JRadioButton rdb1 = new JRadioButton("Value1");

    private void initialize() {
        btn.addActionListener(btnListener);
        rdb1.addActionListener(rb1Listener);
    }

    private final ActionListener btnListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            // something
        }
    };

    private final ActionListener rb1Listener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            // something else
        }
    };
}

答案 3 :(得分:2)

你可以考虑另外两个想法:

  1. 为每个UI元素提供自己的侦听器;他们完全独立。
  2. 将监听器注入Swing UI而不是调用new。您可以让用户有机会根据自己的需要更改行为。让你的Swing UI完成它的目的:显示结果。而已。我认为听众是Controller逻辑的一部分。

答案 4 :(得分:2)

这在一定程度上取决于您在actionPerformed方法中要执行的操作。如果没有其他类可能想要调用此方法,那么我可能会想通过创建内部类来缩小actionPerformed方法的范围,例如: -

public class TestApp {

    private JFrame frame;
    private JButton btn;
    private JRadioButton rdb1;
    private JRadioButton rdb2; 

    private class CombinedActionListener implements ActionListener {
         public void actionPerformed(ActionEvent e) {
             if(e.getSource()==btn)
             //...
             if(e.getSource()==rdb1)
             //...        
             }
    }

    public static void main(String[] args) { /*....*/ }

    private void initialize() {
       ActionListener listener = new CombinedActionListener()

       //Each time I add a button, I add it to the listener:
       btn = new JButton("Button");
       btn.addActionListener(listener);
       //..
       rdb1 = new JRadioButton("Value1");
       rdb1.addActionListener(listener);
       //And so on...
    }
}

您甚至可以通过将按钮实例传递给构造函数来使侦听器类成为静态内部类或顶级类 - 这将使侦听器类更容易测试。

正如我上面所说的,这在很大程度上取决于i)如果其他人可能会调用这种方法而ii)方法内部逻辑的复杂性。