如何在Java中设计ActionListener类?

如何在Java中设计ActionListener类?,java,swing,actionlistener,Java,Swing,Actionlistener,注意:我正在学习干净的代码、设计模式和面向对象编程,所以回答时请记住这一点 我有一个窗口,上面有一堆JButtons和一个TextField。下面是单独文件中的Window类: // Window.java public class Window { JTextField textField; JButton button1; JButton button2; ... } 以下是我想要的: 当我按下button1时,我希望textField显示“1”,当我按下b

注意:我正在学习干净的代码、设计模式和面向对象编程,所以回答时请记住这一点

我有一个窗口,上面有一堆
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");
        }
    }
}
很明显,这是行不通的,所以我的问题是我应该如何定义这个类?

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

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

在您当前的结构中,
窗口
类可以实现
ActionListener
,因为它负责监听视图中的事件。内部类也可以接受,但可能会导致代码更加混乱。你应该警惕过度的关注点分离。您应该只在模型、视图和控制器方面真正地分离代码


一定要检查一下设计模式。

根据您当前的结构,
窗口
类可以实现
ActionListener
,因为它负责监听视图中的事件。内部类也可以接受,但可能会导致代码更加混乱。你应该警惕过度的关注点分离。您应该只在模型、视图和控制器方面真正地分离代码


一定要查看设计模式。

因为监听器类通常需要访问GUI类的字段(如您的
窗口
),所以使用监听器的内部类是一个好主意

当然,并不禁止
Window
实现
ActionListener
,但随后您将在公共API中公开实现细节,您应该考虑是否需要这样做

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

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


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

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

当然,并不禁止
Window
实现
ActionListener
,但随后您将在公共API中公开实现细节,您应该考虑是否需要这样做

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

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


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

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

  • 是否应将
    ActionListener
    实现声明为窗口的内部类我不会的。这是因为当存在与包含类的状态密切相关的功能时,会使用内部类。例如,
    迭代器
    实现可以编写为
    集合
    实现的内部类。在这种情况下,
    迭代器
    实现可以访问
    集合
    实现的私有数据成员。另一个例子是.internal类可以访问父类的私有成员,因此应该谨慎使用
  • 您是否应该为它创建一个单独的类?是的,您应该在一个单独的文件中以最低的访问级别声明它。您不想让
    窗口
    类实现
    ActionListener
    ——仅仅因为这会让窗口类负责处理它包含的所有控件的事件——违反关注点分离(单一责任原则)。因此,想象一下您将要编写的代码-它将充满一长串
    if
    条件或一个用于识别事件源的切换案例。这显然意味着,如果向窗口类添加新控件,则会增加
    if
    switch
    块的长度。在一个单独的类中声明action listener允许分离关注点,也有助于可测试性

希望这有帮助

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

  • 是否应将
    ActionListener
    实现声明为窗口的内部类我不会的。这是因为当存在与包含类的状态密切相关的功能时,会使用内部类。例如,
    迭代器
    实现可以编写为
    集合
    实现的内部类。在这种情况下,
    迭代器
    实现可以访问
    集合
    实现的私有数据成员。另一个例子是.internal类可以访问父类的私有成员,因此应该谨慎使用
  • 您是否应该为它创建一个单独的类?是的,您应该在一个单独的文件中以最低的访问级别声明它。您不想让
    窗口
    类实现
    ActionListener
    ——仅仅因为这会让窗口类负责处理它包含的所有控件的事件——违反关注点分离(单一责任原则)。因此,想象一下您将要编写的代码-它将充满一长串
    if
    条件或一个用于识别事件源的切换案例。这显然意味着,如果向窗口类添加一个新控件,那么
    // 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")
            }
            ...
        }
    }
    
    // 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");
            }
            ...
        }
    }
    
    public void listenTo(Window window) {
            this.window = window;
        }
    
    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");
            }
            ...
        }
    }