博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
观察者模式(一)--《Head First DesignPattern》
阅读量:6922 次
发布时间:2019-06-27

本文共 7451 字,大约阅读时间需要 24 分钟。

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

我们先看下类图:

首先我们自己创建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         //把自己注册给Subject12         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内置了观察者模式相关的接口,可以在下一篇看到相关的实现。

 

 

 

 

转载于:https://www.cnblogs.com/longshaohang/p/3355733.html

你可能感兴趣的文章
oracle错误分析
查看>>
淘宝的OceanBase
查看>>
hbase安装
查看>>
解决Re-download dependencies and sync project
查看>>
Android隐藏输入法软键盘的注意事项
查看>>
Spring框架设计理念与设计模式
查看>>
Windows下MySQL数据库备份脚本(二)
查看>>
算法导论-归并排序
查看>>
用Javascript判断图片是否存在,不存在则显示默认图片的代码
查看>>
Android签名问题,jarsigner的问题
查看>>
Curator Service discovery
查看>>
获取网络数据后缓存到本地,下次从本地获取
查看>>
C#获取本机IP和MAC
查看>>
量子力学崩塌你的“科学”世界观
查看>>
远程桌面之终端服务器超出了最大允许连接数
查看>>
rsync+inotify实现数据的实时同步与备份
查看>>
解决RHEV上传安装源( engine-iso-uploader)异常出错问题解决方案
查看>>
Flex容器综合应用以及皮肤的添加效果
查看>>
一次mysql占用cpu高的处理过程
查看>>
shell脚本中一些特殊符号
查看>>