注意:我正在学习清洁代码,设计模式和面向对象编程,所以请保持在回答时要记住。
我的窗口上有一堆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
,这样可以解决问题)注意:正如您所看到的,问题不是如何做到,而是如何以支持面向对象设计的方式进行。
答案 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
条件或切换案例来识别事件的来源。这显然意味着如果向窗口类添加新控件,则会增加if
或switch
块的长度。在单独的类中声明动作侦听器允许分离关注点并且还有助于可测试性。希望这有帮助
答案 3 :(得分:0)
首先,我要感谢所有回答这个问题的人。没有你我就不会想出来。你们每个人都给了我一个难题。
我最初的问题是:
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");
}
...
}
}