观察者模式其实是比较常用的一种通知模式,即当一个类的属性发生变化要通知其它不等个数的类的时候,常采用这种模式。
在这里我们以java中的Swing中控件间通知为例,也可用于子控件向父控件的变更提示,有点类化于.Net中的委托(delegate).
在观察者模式中,有两个概念:监听者和被监听者,被监听者就是被通知改变的一方,而监听者就是改变通知的一方
比如我们要实现一个自定义的DIalog
里面有两个控件,如下图
上述的对话框中有两个控件,一个jOptionPanel 一个Jlabel,
在这里我们要实现的是在点击JOptionPanel中的确定按钮时,能在下述的label中显示上面的值。
public class TestDialog extends Dialog implents PropertyChangeListener{
private JOptionPanel jOptionPane;
private JTextField jTextField;
private String btnName="确定";
private JLabel jLabel;
public TestDialog(){
Object[] array={jTextField};
Object[] options={btnName};
jOptionPane=new JOptionPane(array,JOptionPane.QUESTION_MESSAGE,JOptionPane.YES_NO_OPTION,null,options,options[0]);
jLabel=new JLable("您在上控件中输入的值为:");
jOptionPanel.addPropertyChangeListener(this);
}
@Override
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (isVisible()
&& (e.getSource() == jOptionPane)
&& (JOptionPane.VALUE_PROPERTY.equals(prop) ||
JOptionPane.INPUT_VALUE_PROPERTY.equals(prop))){
jLabel.setText("您在上控件中输入的值为:"+jTextField.getText());
}
}
}
在这里子控件中有注册事件发生就会通知父控件,并做出想应的改动。保证消息的传递可靠。同样的只要注册的控件,在其数据发生变化都会被通知到。
可能有人会问这个和定义一个回调函数有什么区别,我觉得最大的区别在于,这种方法更加灵活,比如某些时候,一个控件有什么状态变化,如果分别写回调函数的话要很多,而通过该机制, 我们只要自定义命名一个key,然后当其状态变化时,会及时通知注册了的通过propertyChange的evt.getPropertyName()过滤更改。
下面来看一个完整的“委拖”机制的实现。
public class Student
{
public String name;
public Student(String name){
this.name=name;
}
}
public class StuA extends Student{
private Student obserStu;
public StuA(Student obserStu){
super("张三");
this.obserStu=obserStu;
obserStu.addChangeListener(propertyChangeListener);
}
public void stopSleep(){
System.out.println("老师来来,停止睡觉!");
}
private PropertyChangeListener propertyChangeListener=new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
// TODO Auto-generated method stub
if(evt.getPropertyName().equals("teacher")){
stopSleep();
}
}
};
}
public class StuB extends Student{
private Student obserStu;
public StuA(Student obserStu){
super("张三");
this.obserStu=obserStu;
obserStu.addChangeListener(propertyChangeListener);
}
public void stopPlayGame(){
System.out.println("老师来来,停止游戏!");
}
private PropertyChangeListener propertyChangeListener=new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
// TODO Auto-generated method stub
if(evt.getPropertyName().equals("teacher")){
stopPlayGame();
}
}
};
}
public class StuC extends Student{
PropertyChangeSupport propertyChangeSupport=new PropertyChangeSupport(this);
public StuA(){
super("观察者:王五");
}
public void watchTeacher(){
propertyChangeSupport.firePropertyChange("teacher", "go", "stop");
}
public void addChangeListener(PropertyChangeListener propertyChangeListener){
propertyChangeSupport.addPropertyChangeListener(propertyChangeListener);
}
public void removeChangeListener(PropertyChangeListener propertyChangeListener){
propertyChangeSupport.removePropertyChangeListener(propertyChangeListener);
}
}
public class Test{
public static void main(String[] arsgs){
StuC obserStu=new StuC();
Student stuA=new StuA(obserStu);
Student stuB=new StuB(obserStu);
obserStu.watchTeacher();
}
}
不仅观察可以观察老师,甚至是教导主任,家长。。等等,都可以通过PropertyName来区分方法,只要在监听器中加以简单的判断即可,而不用为每一个通知变化都写一个Listener.