繁体   English   中英

如何在Java中设计ActionListener类?

[英]How to design an ActionListener class in Java?

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

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

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

这是我想要的:

当我按下button1我希望textField显示为“ 1”,当我按下button2时显示为“ 2”, button2 。因此,这是单独文件中的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 ,这将解决问题)

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

使用当前结构, Window类可以实现ActionListener因为它负责侦听其视图上的事件。 内部类也可以接受,但可能导致代码混乱。 您应该注意过多的关注点分离。 您应该只在模型,视图和控制器方面真正分开代码。

绝对签出MVC设计模式。

由于侦听器类经常需要使用内部类作为侦听器,因此需要访问GUI类的字段(例如Window )。

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

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

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


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

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

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

希望这可以帮助

首先,我要感谢回答问题的每个人。 没有你,我不会弄清楚。 你们每个人都给我一个难题。

我最初的问题是:

  1. TextInputListener类需要访问buttonX
  2. TextInputListener类需要访问textField

在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");
        }
        ...
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM