Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ActionListener风格-好还是坏_Java_Swing_Coding Style_Inner Classes_Anonymous Class - Fatal编程技术网

Java ActionListener风格-好还是坏

Java ActionListener风格-好还是坏,java,swing,coding-style,inner-classes,anonymous-class,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(Stri

我有一个简单的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)
       //...        
    }
}

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

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

  • 为每个UI元素提供自己的侦听器;这样他们就完全独立了
  • 将侦听器注入Swing UI,而不是调用new。您为用户提供了在他们认为合适时更改行为的机会。让您的Swing UI完成它的本意:显示结果。就这样。我认为侦听器是控制器逻辑的一部分

  • 这在一定程度上取决于您希望在
    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...
        }
    }
    
    您甚至可以通过将button实例传递到构造函数中,使listener类成为静态内部类或顶级类,这将使listener类更易于测试


    正如我上面所说,这在很大程度上取决于I)是否有其他人可能调用此方法,以及ii)方法内部逻辑的复杂性。

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

            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类设置为其他类的侦听器-除非有意这样做,否则这不是一个好的做法。

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

    仅创建一个在事件源组件上切换的侦听器可读性不强,但是,当侦听器的数量增加时,很容易出错。您很容易忘记处理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
            }
        };
    }
    

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

    使用这种风格的监听器的主要好处是,它将准确地隔离动作正在做什么以及它是为谁做的。缺点是当听者包含超过10行或更多行时,因为它开始变得难以阅读和知道听者的实际结束位置

    在这种情况下,类似于内部类的东西可能更合适。它具有匿名类(与使用它的类绑定)的优点,但更易于阅读

    如果您想要可重用的动作(想想像open、new、save这样的动作),那么最好使用API,它提供了自配置性和自包含的动作监听器


    总之,我想知道它到底是好是坏。通过让您的主公共类实现
    ActionListener
    来公开您的
    ActionListener
    是一种糟糕的风格。我只是想知道,为什么你要让你的生活复杂化?简单地说,使用匿名类。我对匿名类不是很熟悉,我会读到它,我会知道它的优点:)谢谢+1一个好问题。我见过一些机构要求学生只使用一个监听器来处理多个性质完全不同的按钮。我很惊讶学校会这么做,因为我一直认为这种处理事件的方式是一个非常坏的习惯。@thdayofcondor No.+1:)如果我的听众很长,我应该像上面展示的那样保持它吗?还是使用匿名类更好?@Maroun85我认为你应该始终使用匿名类。方法中的长侦听器会使方法变得长而混乱,但非匿名类会污染你的系统namespace@Strawberry是的,如果使用if-else来确定是什么控件生成了事件,这是很笨拙的,但不幸的是,这是许多教程中的一种模式,但根据其他答案,每个按钮的匿名类可能是最好的方法。在本例中,它可能是,但使用匿名并不总是如此appropriate@MadProgrammer你说得对。我通常只在最简单的情况下使用匿名类(我在这里假设)。如果有任何复杂的或协作的逻辑,我通常会分解成静态的内部类或包私有的顶级类。我的重点是能够测试逻辑。“大多数面向对象”我会对此进行辩论。您的答案不允许继承实现的类。一个更面向对象的方法是使用一个单独的专用类来实现ActionListener或API-IMHO-请不要,我不是在质疑你的答案,这对于给定的用例是正确的。嗯,也许不是“最面向对象的”,但肯定是“更面向对象的”,而不是一个打开源代码的方法。在不同条件下实现不同行为时,OOP与过程方法通常在使用多态性与条件和开关方面有所不同。“如果您想要可重用的操作…”请注意,每个
    操作
    可能同时用于按钮(或主窗口中的保存按钮,以及两个对话框中的保存按钮)和菜单项。就我的口味而言,这就解决了问题。@AndrewThompson和key bindings;)“密钥绑定”哦,是的……)