如何在Java中设计ActionListener类?

时间:2016-01-15 19:16:58

标签: java swing actionlistener

注意:我正在学习清洁代码设计模式面向对象编程,所以请保持在回答时要记住。

我的窗口上有一堆JButtons和一个TextField。这是单独文件中的Window类:

// Window.java
public class Window {
    JTextField textField;
    JButton button1;
    JButton button2;
    ...
}

这是我想要的:

当我按button1时,我希望textField显示“1”,当我按button2显示“2”等时。所以这里是一个单独文件中的ActionListener类这就是我想要它做的事情:

//TextInputActionListener.java
public class TextInputActionListener implements ActionListener{
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == button1) {
            textField.setText("1");
        }
        else if (e.getSource() == button 2) {
            textField.setText("2");
        }
    }
}

现在显然这不起作用,所以我的问题是我应该如何定义这个类?

  • 我应该将其声明为Window的内部类吗?
  • 我是否应该为它创建一个单独的类?(我可以让Window类实现ActionListener,这样可以解决问题)

注意:正如您所看到的,问题不是如何做到,而是如何以支持面向对象设计的方式进行。

4 个答案:

答案 0 :(得分:1)

使用当前结构,Window类可以实现ActionListener,因为它负责监听其视图中的事件。内部类也是可以接受的,但可能导致更混乱的代码。你应该注意过度分离的顾虑。您应该只根据模型,视图和控制器分离您的代码。

绝对检查MVC设计模式。

答案 1 :(得分:1)

由于监听器类通常需要访问GUI类的字段(如Window),因此使用监听器的内部类是个好主意。

当然不禁止Window实现ActionListener,但是你会在公共API中公开实现细节,你应该考虑是否需要它。

请注意,Java 8的lambdas和方法句柄为您提供了编写侦听器代码的更多可能性:

class Window {
    JTextField textField;
    JButton button1;
    JButton button2;


    Window()
    {
        button1.addActionListener(event -> textField.setText("1"));
        ...
    }
}

答案 2 :(得分:1)

以下是我对这个问题的看法:

  • 是否应将ActionListener实现声明为Window的内部类? - 我不会。这是因为当存在与包含类的状态密切相关的一部分功能时,将使用内部类。对于例如Iterator<E>实现可以编写为Collection<E>实现的内部类。在这种情况下,Iterator实现可以访问Collection实现的私有数据成员。另一个例子是Builder pattern。内部类可以访问父类的私有成员,因此应该小心使用。
  • 你应该为它创建一个单独的类 - 是的,你应该在一个单独的文件中以最低要求的访问级别声明它。您不希望将Window类实现ActionListener - 只是因为这会使Window类负责处理所有它包含控件的事件 - 违规关注点分离(单一责任原则)。因此,想象一下您将编写的代码 - 它将充满一长串if条件或切换案例来识别事件的来源。这显然意味着如果向窗口类添加新控件,则会增加ifswitch块的长度。在单独的类中声明动作侦听器允许分离关注点并且还有助于可测试性。

希望这有帮助

答案 3 :(得分:0)

首先,我要感谢所有回答这个问题的人。没有你我就不会想出来。你们每个人都给了我一个难题。

我最初的问题是:

  1. TextInputListener课程需要访问buttonX
  2. TextInputListener课程需要访问textField
  3. 在TextInputListener类中,我认为它实际上不需要访问按钮,只需要知道e.getSource()是否等于button。所以我在Window类中创建了一个方法,它将ActionEvent作为参数(如e),将其与buttonX进行比较,然后返回返回答案。

    //Window.java
    ...
    boolean isButton0(ActionEvent e) {
        return e.getSource() == buttons[0];
    }
    boolean isButton1(ActionEvent e) {
        return e.getSource() == buttons[1];
    }
    ...
    

    问题1已解决:

    所以现在我离我更近了一步。我可以确定是否按下了button1button2 ..而没有公开按钮,也没有通过像getButton1()这样的“getter”方法返回它。

    // TextInputListener.java
    public class TextInputListener implements ActionListener {
        Window window;
        @Override
        public void actionPerformed(ActionEvent e) {
            if (window.isButton0(e)) {
                //textField.setText("0")
            } else if (window.isButton1(e)) {
                //textField.setText("1")
            }
            ...
        }
    }
    

    TextInputListener.java和Window.java在同一个包中,所以我能够声明方法package-private。

    问题2已解决:

    再次TextInputListener并不真正需要textField(作为变量),只需设置其文本即可。所以我创建了另一个包私有方法setOutputText(String text)来设置文本。这是代码:

    // Window.java
    public class Window {
        TextField textField;
        JButton button1;
        JButton button2;
        ...
        void setText(String text) {
            textField.setText(text);
        }
    }
    
    // TextInputListener.java
    public class TextInputListener implements ActionListener {
        Window window;
        @Override
        public void actionPerformed(ActionEvent e) {
            if (window.isButton0(e)) {
                window.setText("0");
            } else if (window.isButton1(e)) {
                window.setText("1");
            }
            ...
        }
    }
    

    将所有东西放在一起:

    现在唯一剩下的就是让每个类的实例相互了解。在TextInputListener课程中,我添加了以下代码:

    public void listenTo(Window window) {
            this.window = window;
        }
    

    在Window类中,我必须为每个按钮添加ActionListener,所以我添加了以下代码:

    public void setActionListener(ActionListener l) {
            for (int i = 0; i < buttons.length; i++) {
                buttons[i].addActionListener(l);
            }
        }
    

    基本上就是这样!在主要设置一切,它的工作。这是(几乎)完整的最终代码:

    // MyApp.java
    public class MyApp {
        public static void main(String[] args) {
            Window myWindow = new Window();
            TextInputListener myTextInputListener = new TextInputListener();
    
            myWindow.setActionListener(myTextInputListener);
            myTextInputListener.listenTo(myWindow);
        }
    }
    
    // Window.java
    public class Window {
        TextField textField;
        JButton button1;
        JButton button2;
        ...
        void setText(String text) {
            textField.setText(text);
        }
        public void setActionListener(ActionListener l) {
            for (int i = 0; i < buttons.length; i++) {
                buttons[i].addActionListener(l);
            }
        }
    }
    
    // TextInputListener.java
    public class TextInputListener implements ActionListener {
        Window window;
    
        public void listenTo(Window window) {
            this.window = window;
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            if (window.isButton0(e)) {
                window.setText("0");
            } else if (window.isButton1(e)) {
                window.setText("1");
            }
            ...
        }
    }