二.观察者模式(observer)
根据气象站的数据来显示天气预报
其实这个系统分成三部分
1. 气象站(获取气象数据的物理装置)
2. WeatherData对象(追踪气象站数据,并更新布告板)
3. 布告板(当前的天气状况)
WeatherData类的介绍
有个四个method:
温度:getTemperature()
湿度:getHumidity()
气压:getPressure()
mentsChanged():气象参数更新时,这个方法被调用,也就是我们开发代码实装在这个里面
错误的示范:
publicvoid mentsChanged() {
floattemp = getTemperature();
floathumidity = getHumidity();
floatpressure = getPressure();
condision1Display.update(temp,humidity,pressure);
condision2Display.update(temp,humidity,pressure;
condision3Display.update(temp,humidity,pressure);
}
这样做的问题是,每增加或删除一个布告板都会去改动mentsChanged方法。
下面来认识观察者模式:
先举一个例子报纸订阅的问题来类比观察者模式
1. 报社的业务就是出版报纸,每种报纸算一个主题(subject)
2. 你向这家报社订阅报纸,你就成为订户,也就是一个观察者(observer)
只要他们有新报纸出版,你就会收到,也就相当也主题有更新,观察者就会收到通知
3. 当你不再想看报纸的时候,就取消订阅,他们就不会送报纸过来了
就是你解除依赖,不再是观察者了
观察者模式:它定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
类图介绍:
// 主题接口
interface Subject {
//注册为观察者
abstractvoid registerObserver();
//从观察者中删除
abstractvoid removeObserver();
//更新当前所有观察者
abstractvoid notifyObservers();
}
// 观察者接口
interface Subject {
//当主题改变时被调用
abstractvoid update();
}
松耦合概念的介绍
观察者模式提供了一种对象设计,让主题和观察者之间松耦合。
为什么这么说呢?
1. 主题只知道观察者实现了observer接口,其他关于观察者的具体类是什么,做了什么它并不关心。
2. 主题唯一依赖的东西是一个实现observer接口的对象列表,所以我们可以随时增加观察者。
松耦合的设计之所以能让我们建立有弹性的oo系统,能够应对变化,是因为对象之间的互相依赖降到了最低。
开始实现气象站:
主题接口:
public interface Subject {
//
publicvoid registerObserver(Observer o);
//
publicvoid removeObserver(Observer o);
//
publicvoid notifyObservers();
}
观察者接口:
publicinterface Observer {
//
publicvoid update(floattemp, floathumidity, floatpressure);
}
显示接口:
publicinterface DisplayElement {
//
publicvoid display();
}
气象对象:
publicclass WeatherData implementsSubject{
//观察者列表
privateArrayList<Observer> observers;
//
privatefloattemperature;
//
privatefloathumidity;
//
privatefloatpressure;
//
public WeatherData(){
observers= new ArrayList<Observer>();
}
//
publicvoid registerObserver(Observer o){
observers.add(o);
}
//
publicvoid removeObserver(Observer o){
intindex = observers.indexOf(o);
if (index >= 0) {
observers.remove(index);
}
}
//
publicvoid notifyObservers(){
for (inti = 0; i < observers.size(); i++) {
Observer observer = (Observer) observers.get(i);
observer.update(temperature, humidity, pressure);
}
}
//气象参数变化时,通知全部观察者
publicvoid mentsChanged(){
notifyObservers();
}
//手动改变其实参数来更新布告板
publicvoid setMents(floattemperature, floathumidity, floatpressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
mentsChanged();
}
}
一号布告板:
publicclass Condition1Display implements Observer,DisplayElement{
//
privatefloattemperature;
//
privatefloathumidity;
//
privatefloatpressure;
//
private Subject weatherData;
//
public Condition1Display(SubjectweatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
//
publicvoid update(floattemp, floathumidity, floatpressure){
this.temperature = temp;
this.humidity = humidity;
this.pressure = pressure;
//
display();
}
//显示气象参数
publicvoid display() {
System.out.println("temperature:" + temperature + "," + "humidity:" + humidity + "," + "pressure:" + pressure);
}
}
//测试
publicclass WeatherDataTest {
publicstaticvoid main(String[] args) {
//天气对象
WeatherData weatherData = new WeatherData();
//注册一个布告板
Condition1Display condition1Display1 = newCondition1Display(weatherData);
//再注册一个布告板
Condition1Display condition1Display2= new Condition1Display(weatherData);
//天气参数改变
weatherData.setMents(10,20, 30);
}
}
注意一点:有多个观察者的时候,不可有依赖于特定的通知顺序。
Swing大量使用了观察者模式,例如给button追加listener