[英]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
条件或用于确定事件源的开关案例。 显然,这意味着如果向窗口类添加新控件,则会增加if
或switch
块的长度。 在单独的类中声明动作侦听器可以分离关注点,还有助于提高可测试性。 希望这可以帮助
首先,我要感谢回答问题的每个人。 没有你,我不会弄清楚。 你们每个人都给我一个难题。
我最初的问题是:
TextInputListener
类需要访问buttonX
。 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:
所以现在我离我们更近了一步。 我可以确定是否已按下button1
, button2
..,而无需将按钮声明为公共按钮,也无需通过类似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.