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


    观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖着都会受到通知并且自动更新。

    我们先看下类图:

    首先我们自己创建Subject接口,定义了注册观察者,移除观察者和通知观察者三个函数。

    1 package headfirst.observer.weather;
    2 
    3 public interface Subject {
    4     public void registerObserver(Observer o);
    5     public void removeObserver(Observer o);
    6     public void notifyObservers();
    7 }

    而WeatherData实现了这个接口,内部维护的是一个ArrayList的Observer。

     1 package headfirst.observer.weather;
     2 
     3 import java.util.*;
     4 
     5 public class WeatherData implements Subject {
     6     private ArrayList observers;
     7     private float temperature;
     8     private float humidity;
     9     private float pressure;
    10     
    11     public WeatherData() {
    12         observers = new ArrayList();
    13     }
    14     
    15     public void registerObserver(Observer o) {
    16         observers.add(o);
    17     }
    18     
    19     public void removeObserver(Observer o) {
    20         int i = observers.indexOf(o);
    21         if (i >= 0) {
    22             observers.remove(i);
    23         }
    24     }
    25     
    26     public void notifyObservers() {
    27         for (int i = 0; i < observers.size(); i++) {
    28             Observer observer = (Observer)observers.get(i);
    29             observer.update(temperature, humidity, pressure);
    30         }
    31     }
    32     
    33     public void measurementsChanged() {
    34         notifyObservers();
    35     }
    36     
    37     public void setMeasurements(float temperature, float humidity, float pressure) {
    38         this.temperature = temperature;
    39         this.humidity = humidity;
    40         this.pressure = pressure;
    41         measurementsChanged();
    42     }
    43     
    44     public float getTemperature() {
    45         return temperature;
    46     }
    47     
    48     public float getHumidity() {
    49         return humidity;
    50     }
    51     
    52     public float getPressure() {
    53         return pressure;
    54     }
    55 }

    DisplayElement接口只包含了一个方法,也就是display()。但布告板需要显示时,调用此方法。

    1 package headfirst.observer.weather;
    2 
    3 public interface DisplayElement {
    4     public void display();
    5 }

    Observer接口定义了update函数,当Subject的内容发生改变时,会调用update函数来通知观察者更新状态值。

    1 package headfirst.observer.weather;
    2 
    3 public interface Observer {
    4     public void update(float temp, float humidity, float pressure);
    5 }

    观察者需要存储Subject的引用,通过这个引用来进行注册。

     1 package headfirst.observer.weather;
     2     
     3 public class CurrentConditionsDisplay implements Observer, DisplayElement {
     4     private float temperature;
     5     private float humidity;
     6     private Subject weatherData;
     7     
     8     //构造函数的参数为Subject
     9     public CurrentConditionsDisplay(Subject weatherData) {
    10         this.weatherData = weatherData;
    11         //把自己注册给Subject
    12         weatherData.registerObserver(this);
    13     }
    14     
    15     //更新时调用相应的display函数
    16     public void update(float temperature, float humidity, float pressure) {
    17         this.temperature = temperature;
    18         this.humidity = humidity;
    19         display();
    20     }
    21     
    22     public void display() {
    23         System.out.println("Current conditions: " + temperature 
    24             + "F degrees and " + humidity + "% humidity");
    25     }
    26 }
    27         

    其他两个差不多:

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

    StatisticsDisplay

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

    HeadDisplay

     1 package headfirst.observer.weather;
     2 
     3 public class HeatIndexDisplay implements Observer, DisplayElement {
     4     float heatIndex = 0.0f;
     5     private WeatherData weatherData;
     6 
     7     public HeatIndexDisplay(WeatherData weatherData) {
     8         this.weatherData = weatherData;
     9         weatherData.registerObserver(this);
    10     }
    11 
    12     public void update(float t, float rh, float pressure) {
    13         heatIndex = computeHeatIndex(t, rh);
    14         display();
    15     }
    16     
    17     private float computeHeatIndex(float t, float rh) {
    18         float index = (float)((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh) 
    19             + (0.00941695 * (t * t)) + (0.00728898 * (rh * rh)) 
    20             + (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) +
    21             (0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 * 
    22             (rh * rh * rh)) + (0.00000142721 * (t * t * t * rh)) + 
    23             (0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) +
    24             0.000000000843296 * (t * t * rh * rh * rh)) -
    25             (0.0000000000481975 * (t * t * t * rh * rh * rh)));
    26         return index;
    27     }
    28 
    29     public void display() {
    30         System.out.println("Heat index is " + heatIndex);
    31     }
    32 }

    接下来就是main函数了。

     1 package headfirst.observer.weather;
     2 
     3 import java.util.*;
     4 
     5 public class WeatherStationHeatIndex {
     6 
     7     public static void main(String[] args) {
     8         WeatherData weatherData = new WeatherData();
     9         CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
    10         StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
    11         ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
    12         HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData);
    13 
    14         weatherData.setMeasurements(80, 65, 30.4f);
    15         weatherData.setMeasurements(82, 70, 29.2f);
    16         weatherData.setMeasurements(78, 90, 29.2f);
    17     }
    18 }

    可以看到这里实现的Observer模式有两个要注意的地方

    1. “推”模式,Subject内容一有变化,就主动向Observer推送消息。它是通过在Subject中的notifyObservers中对每个Observer调用update来实现的。如果要实现“拉”模式,因为在Observer保存了Subject的引用,所以可以通过定时的方式,向Subject拉取数据。
    2. 可以看到update函数是依赖于具体实现的,可以看到参数是什么温度,湿度等等。这样的接口是无法面向所有的应用的。不过Java内置了观察者模式相关的接口,可以在下一篇看到相关的实现。
  • 相关阅读:
    JavaScript OOP 思想
    单页界面和 AJAX 模式
    jQuery 的 ready 函数是如何工作的?
    Dojo系列教程
    谈谈javascript语法里一些难点问题(一)
    2014年总结、2015年的小计划--女生程序员小感想
    Android名词解释
    【JS】defer / async
    关于对defer的理解.
    defer和async的区别
  • 原文地址:https://www.cnblogs.com/longshaohang/p/3355733.html
Copyright © 2020-2023  润新知