感觉上一章写的太磨叽,还没说重点,这一张我就直接把观察者模式写出来,并对java中的涉及到的Observable类和Observe接
口进行说明:
观察者模式四个组成部分:
Subject主题----------ConcreteSubject具体的主题
Observer观察者(抽象的观察主题的对象)----------ConcreteObserver具体的观察者
(在java中java.util.Observer接口就是封装好的Subject主题,java.util.Observable类是封装好的观察者对象)
观察者模式起到的作用是,当主题发生改变,观察主体的对象们都会获得通知,这种通知的形式都是主题主动推给观察的人,而不是观察者过来恳求主题给他们的。
下边的例子是一个气象站(主题),监测这环境的温度、湿度、气压等一系列资料,一旦有变动,布告栏(观察者们)会实时的更改他们展示给大众的数据。
public interface Subject { public void registerObserver(Observer o); //添加观察者到主题内部的观察者集合中(每次有改变,主题就到自己的这个集合中,遍历调用方法告诉观察者们) public void removeObserver(Observer o); //删除集合中的某个观察者 public void notifyObservers(); //通知所有的观察者(这一步就是前边说的遍历通知) }
public interface Observer { public void update(float temp, float humidity, float pressure); //这个方法是主题变化时会调用所有注册的观察者的此方法,来进行数据推送 }
public class WeatherData implements Subject { private ArrayList observers; //这就是那个记录着所有观察者的集合,主题手里的小本本,记录了所有要通知的人 //temperature、humidity、pressure就是WeatherData的“状态” private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList(); } public void registerObserver(Observer o) { observers.add(o); } public void removeObserver(Observer o) { int i = observers.indexOf(o); if (i >= 0) { observers.remove(i); } } public void notifyObservers() { for (int i = 0; i < observers.size(); i++) { Observer observer = (Observer)observers.get(i); observer.update(temperature, humidity, pressure); } } public void measurementsChanged() { notifyObservers(); } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } public float getTemperature() { return temperature; } public float getHumidity() { return humidity; } public float getPressure() { return pressure; } }
public interface DisplayElement { //这个接口是布告板的东西,里面的展示功能是让不同的布告板去实现的,跟模式没什么关系 public void display(); }
public class StatisticsDisplay implements Observer, DisplayElement { //这是第一个布告板,实时监测气象站记录的数据 private float maxTemp = 0.0f; private float minTemp = 200; private float tempSum= 0.0f; private int numReadings;//记录观测的次数以便计算平均温度值 private Subject weatherData; //下边几个布告板都会带有主题的对象引用,作用就是能够利用它调用主题的注册、删除观察者的方法,实现监听和放弃监听 public StatisticsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } //这属于“推”数据,本类只使用到了第一个参数 public void update(float temp, float humidity, float pressure) { tempSum += temp; numReadings++; if (temp > maxTemp) { maxTemp = temp; } if (temp < minTemp) { minTemp = temp; } display(); } public void display() { System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings) + "/" + maxTemp + "/" + minTemp); } }
public class CurrentConditionsDisplay implements Observer, DisplayElement {
//这是第二个布告板,实时监测气象站记录的数据
private float temperature;//温度
private float humidity;//湿度private Subject weatherData; public CurrentConditionsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } //推数据,这里只使用到了前两个参数 public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; display(); } public void display() { System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity"); } }
public class ForecastDisplay implements Observer, DisplayElement {
//这是第三个布告板,实时监测气象站记录的数据private float currentPressure = 29.92f; private float lastPressure; private Subject weatherData; public ForecastDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } public void update(float temp, float humidity, float pressure) { lastPressure = currentPressure; currentPressure = pressure; display(); } public void display() { System.out.print("Forecast: "); if (currentPressure > lastPressure) { System.out.println("Improving weather on the way!"); } else if (currentPressure == lastPressure) { System.out.println("More of the same"); } else if (currentPressure < lastPressure) { System.out.println("Watch out for cooler, rainy weather"); } } }
结果展示:
public class WeatherStationHeatIndex { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData); weatherData.setMeasurements(80, 65, 30.4f); //这里就是模拟的气象站监测数据的变化,人为给了变化的值 weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); } }
java提供的Observable类和Observe接口里还有一个标志位,用作判断主体是否改变
https://blog.csdn.net/suool/article/details/39473055具体的可以看这篇文章。
java提供的这两个的缺陷:Observable是一个具体实现类,面向细节了,而未面向抽象,使用Observable时需要使用继承,由于java的类单继承性,如果你的类已经继承了一个类,将不能继承Observable来实现观察者模式,并且由于setChanged和clearChanged方法都是protected的,所以你也不能通过组合来完成观察者模式