[英]How to design an ActionListener class in Java?
NOTE: I'm learning about Clean Code , Design Patterns and Object Oriented Programming so please keep that in mind when answering. 注意:我正在学习“ 干净代码” ,“ 设计模式”和“ 面向对象的编程”,因此在回答时请记住这一点。
I've got a window with bunch of JButtons
and a TextField
on the top. 我有一个窗口,上面有一堆
JButtons
和一个TextField
。 Here's the Window class in its separate file: 这是Window类的单独文件:
// Window.java
public class Window {
JTextField textField;
JButton button1;
JButton button2;
...
}
Here's what I'd like: 这是我想要的:
When I press button1
I want the textField
to display "1", when I press button2
to display "2", etc. So here's the ActionListener class in a separate file and this is sort of what I want it to do: 当我按下
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");
}
}
}
Now obviously this wont work, so my question is how should I define this class? 现在显然这将行不通,所以我的问题是我应该如何定义此类?
Window
? Window
的内部类吗? Window
class implement ActionListener
and that would solve the problem) Window
类实现ActionListener
,这将解决问题) NOTE: As you can see the question is not how to do it but rather, how to do it in a way that supports Object Oriented Design. 注意:正如您所看到的,问题不在于如何执行,而是如何以支持面向对象设计的方式来执行。
With your current structure, the Window
class can implement ActionListener
because it is responsible for listening to events on its view. 使用当前结构,
Window
类可以实现ActionListener
因为它负责侦听其视图上的事件。 An inner class would also be acceptable but could lead to more cluttered code. 内部类也可以接受,但可能导致代码混乱。 You should be watchful of excessive separation of concerns.
您应该注意过多的关注点分离。 You should only really separate your code in terms of the Model, the View, and the Controller.
您应该只在模型,视图和控制器方面真正分开代码。
Since listener classes often need access to fields of GUI classes (like your Window
) using inner classes for listeners is a good idea. 由于侦听器类经常需要使用内部类作为侦听器,因此需要访问GUI类的字段(例如
Window
)。
Of course it is not forbidden that Window
implements ActionListener
but you then expose implementation details in the public API and you should think if you want that. 当然,并非禁止
Window
实现ActionListener
但是您随后在公共API中公开了实现细节,您应该考虑是否要这样做。
Note that lambdas and method handles of Java 8 give you even more possibilities to write listener code: 请注意,Java 8的lambda和方法句柄为您提供了更多编写侦听器代码的可能性:
class Window {
JTextField textField;
JButton button1;
JButton button2;
Window()
{
button1.addActionListener(event -> textField.setText("1"));
...
}
}
Here is my take on this problem : 这是我对这个问题的看法:
ActionListener
implementation be declared as an inner class of Window? ActionListener
实现声明为Window的内部类? - I would not. Iterator<E>
implementation can be written as an inner class of Collection<E>
implementation. Iterator<E>
实现编写为Collection<E>
实现的内部类。 In this case the Iterator
implementation has access to the private data members of the Collection
implementation. Iterator
实现可以访问Collection
实现的私有数据成员。 Another example is the Builder pattern .Inner classes have access to the private members of the parent class and hence should be used with care. Window
class implement ActionListener
- simply because this would make the Window class responsible to handle events for all it's containing controls - violation of the separation of concerns (Single Responsibility Principle). Window
类实现ActionListener
-仅仅因为这会使Window类负责处理所有包含控件的事件-违反关注点分离(单一责任原则)。 So imagine the code you would be writing - it would be fraught with a long list of if
conditions or a switch case to identify the source of the event. if
条件或用于确定事件源的开关案例。 This obviously implies that if you add a new control to the window class you increase the length of the if
or switch
block. if
或switch
块的长度。 Declaring the action listener in a separate class allows for separations of concerns and also helps testability. Hope this helps 希望这可以帮助
First of all I'd like to thank everybody who answered the question. 首先,我要感谢回答问题的每个人。 Without you I would've not figured it out.
没有你,我不会弄清楚。 Each one of you gave me a piece of the puzzle.
你们每个人都给我一个难题。
My initial problems were: 我最初的问题是:
TextInputListener
class needs access to buttonX
. TextInputListener
类需要访问buttonX
。 TextInputListener
class needs access to textField
. TextInputListener
类需要访问textField
。 In the TextInputListener class I figured that it doesn't really need access to the buttons, it only has to know if e.getSource()
equals button
. 在TextInputListener类中,我认为它实际上不需要访问按钮,只需要知道
e.getSource()
等于button
。 So I created methods in the Window
class that takes an ActionEvent
as a parameter (like e
), compares it to buttonX
and returns returns the answer. 因此,我在
Window
类中创建了将ActionEvent
作为参数的方法(例如e
),将其与buttonX
进行比较并返回返回答案。
//Window.java
...
boolean isButton0(ActionEvent e) {
return e.getSource() == buttons[0];
}
boolean isButton1(ActionEvent e) {
return e.getSource() == buttons[1];
}
...
PROBLEM 1 SOLVED: 解决的问题1:
So now I'm one step closer. 所以现在我离我们更近了一步。 I can determine whether
button1
, button2
.. was pressed, without declaring the buttons public or without returning it by a "getter" method like getButton1()
. 我可以确定是否已按下
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 and Window.java are in the same package so I was able to declare the methods package-private. ) ( TextInputListener.java和Window.java在同一程序包中,因此我可以将方法声明为package-private。 )
PROBLEM 2 SOLVED: 解决的问题2:
Once again TextInputListener
didn't really need textField
(as a variable) it just needed to set its text. 同样,
TextInputListener
并不需要真正的textField
(作为变量),只需要设置其文本即可。 So I created another package-private method setOutputText(String text)
for setting the text. 因此,我创建了另一个程序包专用方法
setOutputText(String text)
来设置文本。 Here's the code: 这是代码:
// 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");
}
...
}
}
PUTTING EVERYTHING TOGETHER: 将所有内容放在一起:
The only thing that's left now is to let each instance of the class to know about each other. 现在剩下的唯一事情就是让该类的每个实例相互了解。 In
TextInputListener
class I added the following code: 在
TextInputListener
类中,我添加了以下代码:
public void listenTo(Window window) {
this.window = window;
}
In the Window class I had to add the ActionListener
to each button, so I added the following code: 在Window类中,我必须将
ActionListener
添加到每个按钮,因此添加了以下代码:
public void setActionListener(ActionListener l) {
for (int i = 0; i < buttons.length; i++) {
buttons[i].addActionListener(l);
}
}
That's basically it! 基本上就是这样! In main set everything up and it's working.
在主要设置中,一切正常,并且正在运行。 Here's the (almost) full final code:
这是(几乎)完整的最终代码:
// 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.