1 观察者模式概述
观察者模式定义了数据对象之间一对多的依赖关系,当中心对象发生变化时,所有依赖该中心对象的数据对象会收到通知并自动更新。为了更加形象的描述本模式,可以用报纸订阅服务来比拟。
报纸服务是这样的:
1 报社出版报纸
2 用户向报社订阅报纸,只要报社有新报纸就通知用户收取新报纸
3 用户向报社取消订阅,那么报社就不在通知用户收取报纸
4 只要报社没有倒闭,就一直会有人订阅报纸
在这里,报社称为“主题”(subject),订阅报纸的用户称为“观察者”(observer)。报社+订阅者=观察者模式。下图可以形象的描述观察者模式的流程:
2 观察者模式角色组成
观察者模式一般拥有四种角色:抽象主题,具体主题,抽象观察者和具体观察者。
抽象主题是一个接口,把所有观察者对象的引用保存在一个聚集里。
具体主题,实现抽象主题中接口
抽象观察者:所有观察者必须实现观察者接口,这个接口只有一个update()方法,当主题状态变化时被调用。
具体观察者:实现抽象观察者接口。
观察者模式类图:
3 代码实现:
下面结合实例,实现观察者模式代码。
事例描述:气象站追踪气象数据(温度,湿度,气压),更新发布版中气象数据。
类图:
根据类图编写代码,首先实现抽象主题代码:
public interface Subject {
public void registerObserver(Observer o);//注册观察者
public void removeObserver(Observer o);//删除观察者
public void notifyObserver();//当主题对象数据发生变化时,被调用
}
抽象观察者:
public interface Observer {
public void update(float temperature,float humidity,float pressure);
}
public interface DisplayElement {
public void display();
}
主题对象WeatherData:
WeatherData对象实现了Subject接口。使用ArrayList来存储Observer对象,当注册观察者时,只要把它加到ArrayList后面即可。notifyObserver方法为把现在的状态通知到每一个观察者,因为每一个观察者都实现了update方法。
package observer.weather;
import java.util.ArrayList;
public class WeatherData implements Subject{
private ArrayList observer;
private float temperature;
private float humidity;
private float pressure;
public WeatherData(){
observer = new ArrayList();
}
@Override
public void registerObserver(Observer o) {
// TODO Auto-generated method stub
observer.add(o);
}
@Override
public void removeObserver(Observer o) {
// TODO Auto-generated method stub
int i = observer.indexOf(o);
if(i>=0){
observer.remove(i);
}
}
@Override
public void notifyObserver() {
// TODO Auto-generated method stub
for(int i=0;i<observer.size();i++){
Observer ob = (Observer) observer.get(i);
ob.update(temperature, humidity, pressure);
}
}
public void measurementsChanged(){
notifyObserver();
}
public void setMeasurements(float temperature,float humidity,float pressure){
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
measurementsChanged();
}
}
观察者对象:
package observer.weather;
public class CurrentConditionDisplay implements Observer,DisplayElement{
private float tempetature;
private float humidity;
private float pressure;
private Subject weatherData;
//注册观察者
public CurrentConditionDisplay(Subject weatherData){
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("tempetature="+tempetature+" humidity="+humidity+" perssure="+pressure);
}
@Override
public void update(float temperature, float humidity, float pressure) {
// TODO Auto-generated method stub
this.tempetature=temperature;
this.humidity=humidity;
this.pressure=pressure;
display();<pre name="code" class="java"><span style="font-family: Helvetica, 'Hiragino Sans GB', 微软雅黑, 'Microsoft YaHei UI', SimSun, SimHei, arial, sans-serif; widows: auto;"> }</span>
}
最后建立一个测试程序:
package observer.weather;
public class WeatherStation {
public static void main(String[] args) {
// TODO Auto-generated method stub
WeatherData weatherData = new WeatherData();
CurrentConditionDisplay currentConditionDisplay =
new CurrentConditionDisplay(weatherData);
weatherData.setMeasurements(12, 0, 1);
weatherData.setMeasurements(1, 10, 11);
weatherData.setMeasurements(19, 13, 31);
}
}
运行结果: