监听器模式又称观察者模式(Observer),这种模式完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。
所谓设计模式其实是一种思想,它不限于特定的场景里,而是体现在软件设计的方方面面。下面用一种最简单的使用场景来体现一下监听器模式。
比如这里有一个简单的窗口,现在的需求是当用户点击按钮时能改变标签的文本。
实现起来很简单,按以往的套路,我们只需在界面类创建并添加好这些组件,然后给按钮添加事件监听即可,部分代码如下:
label = new JLabel("标签");
button = new JButton("按钮");
button.addActionListener(new MyActionListener(label));
动作事件监听器的代码如下:
public class MyActionListener implements ActionListener{
private JLabel label;
public MyActionListener(JLabel label) {
this.label = label;
}
@Override
public void actionPerformed(ActionEvent arg0) {
label.setText("改变文本");
}
}
这样就可以改变标签的文本了。但是因为需求是不断变化的,突然需求改了,变成要当用户点击按钮时改变文本框的文本,按以前的思路,这时应该将监听器里面的JLabel改为JTextField,然后将JTextField对象传递进来。改变代码如下:
public class MyActionListener implements ActionListener{
// private JLabel label;
private JTextField textField;//需求改变拉
public MyActionListener(JTextField textField) {
// this.label = label;
this.textField = textField;
}
@Override
public void actionPerformed(ActionEvent arg0) {
// label.setText("改变文本");
textField.setText("改变文本");
}
}
当然还要把界面里面添加动作事件监听的参数改成JTextField。这样就实现了这个需求,然而我们注意到,这个问题虽然小,但是假使这个界面还有很多组件呢,用户不断变更需求,难道我们也要跟着不断地修改代码?在上面的例子中,一旦用户修改文本的组件变更,我们需要修改界面和监听两个部分的代码,这样这两个模块的耦合度就非常高,也不利于代码的维护。
这个时候我们就可以使用监听器模式的思想,我们可以想到,每个组件都用到改变文本这个方法,是不是可以定义一个接口,用来处理改变文本:
public interface ChangeTextInterface {
//改变文本
public void changeText();
}
对于想改变文本的组件,只需让它们实现这个接口即可,这里就用到自定义组件了,它有父类的功能,并提高了可扩展性,以JLabel为例:
public class MyJLabel extends JLabel implements ChangeTextInterface{
public MyJLabel(String text){
super(text);
}
@Override
public void changeText() {
setText("改变文本");
}
}
JTextField也是同理,而监听器只需接收一个实现了ChangeTextInterface的组件即可,而不用管具体是哪一种组件,修改如下:
public class MyActionListener implements ActionListener{
private ChangeTextInterface whatever;//不管是哪个组件
public MyActionListener(ChangeTextInterface whatever) {
this.whatever = whatever;
}
@Override
public void actionPerformed(ActionEvent arg0) {
//调用改变文本方法即可
whatever.changeText();
}
}
在窗体中,我们只要创建自定义组件即可:
myLabel = new MyJLabel("标签");
button = new JButton("按钮");
button.addActionListener(new MyActionListener(myLabel));
这样,不管用户想改变什么的文本,只要创建一个自定义组件并传进去即可,就不用改变监听器的代码了。