观察者模式(二)--《Head First DesignPattern》

我们用Java中自带的观察者模式接口来重写前面的例子。

先看一下类图:

这里用到了一个setChanged函数,它用来标记状态已经改变的事实,好让notifyObservers()知道当它调用时就应该更新观察者。如果调用notifyObservers()之前没有先调用setChanged(),观察者就不会被通知到。setChanged()方法可以让你在更新观察者时,有更大的弹性,你可以适当地通知观察者。

Observable内部是这样的结构:

setChanged(){
 changed = true;      
}

notifyObservers(Object arg){
 if (changed){
   for every observer on the list{
      call update(this, arg)       
  } } } notifyObservers(){ notifyObservers(
null); }

 注意这里是继承Observable类,而不是接口

 1 package headfirst.observer.weatherobservable;
 2     
 3 import java.util.Observable;
 4 import java.util.Observer;
 5     
 6 public class WeatherData extends Observable {
 7     private float temperature;
 8     private float humidity;
 9     private float pressure;
10     
11     public WeatherData() { }
12     
13     public void measurementsChanged() {
14         //设置changed变量
15         setChanged();
16         notifyObservers();
17     }
18     
19     public void setMeasurements(float temperature, float humidity, float pressure) {
20         this.temperature = temperature;
21         this.humidity = humidity;
22         this.pressure = pressure;
23         measurementsChanged();
24     }
25     
26     public float getTemperature() {
27         return temperature;
28     }
29     
30     public float getHumidity() {
31         return humidity;
32     }
33     
34     public float getPressure() {
35         return pressure;
36     }
37 }
38     

观察者实现Observer接口,

 1 package headfirst.observer.weatherobservable;
 2 
 3 import java.util.Observable;
 4 import java.util.Observer;
 5     
 6 public class CurrentConditionsDisplay implements Observer, DisplayElement {
 7     Observable observable;
 8     private float temperature;
 9     private float humidity;
10     
11     public CurrentConditionsDisplay(Observable observable) {
12         this.observable = observable;
13         observable.addObserver(this);
14     }
15     
16     public void update(Observable obs, Object arg) {
17         if (obs instanceof WeatherData) {
18             WeatherData weatherData = (WeatherData)obs;
19             this.temperature = weatherData.getTemperature();
20             this.humidity = weatherData.getHumidity();
21             display();
22         }
23     }
24     
25     public void display() {
26         System.out.println("Current conditions: " + temperature 
27             + "F degrees and " + humidity + "% humidity");
28     }
29 }

ForecastDisplay

 1 package headfirst.observer.weatherobservable;
 2 
 3 import java.util.Observable;
 4 import java.util.Observer;
 5 
 6 public class ForecastDisplay implements Observer, DisplayElement {
 7     private float currentPressure = 29.92f;  
 8     private float lastPressure;
 9 
10     public ForecastDisplay(Observable observable) {
11         observable.addObserver(this);
12     }
13 
14     public void update(Observable observable, Object arg) {
15         if (observable instanceof WeatherData) {
16             WeatherData weatherData = (WeatherData)observable;
17             lastPressure = currentPressure;
18             currentPressure = weatherData.getPressure();
19             display();
20         }
21     }
22 
23     public void display() {
24         System.out.print("Forecast: ");
25         if (currentPressure > lastPressure) {
26             System.out.println("Improving weather on the way!");
27         } else if (currentPressure == lastPressure) {
28             System.out.println("More of the same");
29         } else if (currentPressure < lastPressure) {
30             System.out.println("Watch out for cooler, rainy weather");
31         }
32     }
33 }

 

 1 package headfirst.observer.weatherobservable;
 2 
 3 import java.util.Observable;
 4 import java.util.Observer;
 5 
 6 public class StatisticsDisplay implements Observer, DisplayElement {
 7     private float maxTemp = 0.0f;
 8     private float minTemp = 200;
 9     private float tempSum= 0.0f;
10     private int numReadings;
11 
12     public StatisticsDisplay(Observable observable) {
13         observable.addObserver(this);
14     }
15 
16     public void update(Observable observable, Object arg) {
17         if (observable instanceof WeatherData) {
18             WeatherData weatherData = (WeatherData)observable;
19             float temp = weatherData.getTemperature();
20             tempSum += temp;
21             numReadings++;
22 
23             if (temp > maxTemp) {
24                 maxTemp = temp;
25             }
26  
27             if (temp < minTemp) {
28                 minTemp = temp;
29             }
30 
31             display();
32         }
33     }
34 
35     public void display() {
36         System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings)
37             + "/" + maxTemp + "/" + minTemp);
38     }
39 }

main函数

 1 package headfirst.observer.weatherobservable;
 2 
 3 public class WeatherStation {
 4 
 5     public static void main(String[] args) {
 6         WeatherData weatherData = new WeatherData();
 7         CurrentConditionsDisplay currentConditions = new CurrentConditionsDisplay(weatherData);
 8         StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
 9         ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
10 
11         weatherData.setMeasurements(80, 65, 30.4f);
12         weatherData.setMeasurements(82, 70, 29.2f);
13         weatherData.setMeasurements(78, 90, 29.2f);
14     }
15 }

这里还是要注意几点:

  1. java.util.Observable是一个“类”而不是一个“接口”,所以我们的类必须继承它,这带来的问题就是Java中只有单继承,所以这限制了Observable的复用能力。而且Observable中的setChanged是被设置为protected的,所以除非你继承自Observable,否则你无法创建Observable实例并把它组合到我们的对象中来。如果实在不行,还是建立我们自己实现一套自己的接口,类似于第一篇所说的。
  2. Java中的Swing的API就用到了观察者模式。例如我们有一个JButton对象,然后给他设置监听器。这里的监听器就是一个Observer,而JButton就是一个主题。当在JButton上有对应的事件发生的时候,例如点击,那么就会通知监听器,调用类似于update的方法,其实就是ActionListener中的actionPerformed()方法。

 

 

 

posted @ 2013-10-07 19:45  longshaohang  阅读(322)  评论(0编辑  收藏  举报