1. 用内部类和闭包实现监听器:
1) 之前讲的所有形式都是内部类实现监听器,即在类内部定义一个监听器;
2) 但最常用的还是闭包了,即匿名内部类和Lambda表达式:
i. 因为监听器通常都是临时使用的代码,往往不会在其它地方被复用;
ii. 即使要复用肯定会被抽象到业务逻辑层面单独编写;
iii. 因此通常为了方便会用匿名内部类或者Lambda表达式来实现监听器;
3) 匿名内部类示例:
Frame f = new Frame("Test");
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// TODO Auto-generated method stub
// super.windowClosing(e);
System.exit(0);
}
});
!!由于WindowAdapter不只有一个方法(7个),因此不是函数式接口,不能使用Lambda表达式;
4) Lambda表达式:只适用于函数是接口,注意!函数式监听器接口(ActionListener等)没有对应的适配器,因为只有一个方法,没必要提供适配器
Button btn = new Button("button");
btn.addActionListener(e -> System.out.println(e.getActionCommand()));
2. 反射:
1) 反射一词来自MFC,即组件自己监听自己的意思,这种组件就是智能组件,这种反射就叫做组件反射;
2) 当然在Java中就是让类自己来监听自己的组件,这就叫类反射,当然MFC式的组件反射也可以实现;
3) 反射的示例:类反射和组件反射
public class AwtTest extends WindowAdapter { // 类自己监听自己的组件
Frame f = new Frame("WindowAdapter Test");
class MyButton extends Button implements ActionListener { // 组件自己监听自己
public MyButton(String label) throws HeadlessException {
super(label);
// TODO Auto-generated constructor stub
this.addActionListener(this); // 组件自反射
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
System.out.println("Button pushed!");
}
}
@Override
public void windowClosing(WindowEvent e) {
// TODO Auto-generated method stub
System.exit(0);
}
public void init() {
f.addWindowListener(this); // 类自反射
f.add(new MyButton("button"));
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
new AwtTest().init();
}
}
!像这样的按钮只要new出来随便用就行了,它产生的事件都由它自己来处理(自定义按钮);
!!注意this的应用是实现反射的关键;
4) 反射的缺点:
i. 通常组件、GUI类(用于显示界面的类,上面的类就是GUI类,PS:其实组件也是GUI类,用于显示组件本身)就只负责显示界面;
ii. 监听、处理事件应该放到另一个模块来处理,因为这符合MVC设计思想;
iii. 因此反射的缺点就是程序结构混乱,模块耦合度高;
3. 外部:
1) 将监听器单独定义成外部类,然后GUI界面调用它;
2) 最大的缺点:
i. 监听器通常属于特定的GUI界面,定义在外部降低了程序的内聚性;
ii. 外部类不能自由访问GUI界面类中的数据(组件),编程不简洁;
3) 示例:监听邮件发送按钮的监听器定义在外部
i. 监听器:
public class MailerListener implements ActionListener {
private TextField mailAdress;
public MailerListener() {}
public MailerListener(TextField mailAdress) {
this.mailAdress = mailAdress;
}
public TextField getMailAdress() {
return mailAdress;
}
public void setMailAdress(TextField mailAdress) {
this.mailAdress = mailAdress;
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
System.out.println("sending mail to '" + mailAdress.getText() + ".'\n");
}
}
ii. GUI:
public class AwtTest extends WindowAdapter { // 类自己监听自己的组件
@Override
public void windowClosing(WindowEvent e) {
// TODO Auto-generated method stub
// super.windowClosing(e);
System.exit(0);
}
public void init() {
Frame f = new Frame("Sending Mail Test");
TextField tf = new TextField(40);
Button btn = new Button("send");
f.addWindowListener(this);
btn.addActionListener(new MailerListener(tf));
f.add(tf);
f.add(btn, BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
new AwtTest().init();
}
}
!!可以看到监听器和GUI之间存在数据的共享,这加大了模块之间的耦合度,这无疑是对程序健壮性的一种危害!!要慎重使用;