Book Notes

The Observer Pattern: defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.

Design Pattern:

Example

Publisher

需要提供注册、注销、通知观察者的接口。

WeatherData 是 publisher 的实现类。

// publisher interface
public interface Subject {
	public void registerObserver(Observer o);
	public void removeObserver(Observer o);
	public void notifyObservers();
}

// publisher implementation
public class WeatherData implements Subject {
	private List<Observer> observers; // 观察者列表
	private float temperature;
	private float humidity;
	private float pressure;
	
	public WeatherData() {
		observers = new ArrayList<Observer>();
	}
	
	public void registerObserver(Observer o) { // 注册观察者
		observers.add(o);
	}
	
	public void removeObserver(Observer o) { // 注销观察者
		observers.remove(o);
	}
	
	public void notifyObservers() { // 通知观察者
		for (Observer observer : observers) {
			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;
	}

}

Observer

需要提供一个 update 函数,当 publisher 通知观察者时,会统一调用这个函数。

// observer interface
public interface Observer {
	public void update(float temp, float humidity, float pressure);
}

public interface DisplayElement {
	public void display();
}

// observer 1
public class CurrentConditionsDisplay implements Observer, DisplayElement {
	private float temperature;
	private float humidity;
	private WeatherData weatherData;
	
	public CurrentConditionsDisplay(WeatherData 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() { // 每个 observer 都有自己不同的 display 函数,用于显示数据
		System.out.println("Current conditions: " + temperature 
			+ "F degrees and " + humidity + "% humidity");
	}
}

// observer 2
public class ForecastDisplay implements Observer, DisplayElement {
	private float currentPressure = 29.92f;  
	private float lastPressure;
	private WeatherData weatherData;

	public ForecastDisplay(WeatherData 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");
		}
	}
}

test code:

// test code
public class WeatherStation {
	public static void main(String[] args) {
		WeatherData weatherData = new WeatherData();
	
		CurrentConditionsDisplay currentDisplay = 
			new CurrentConditionsDisplay(weatherData);
		ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);

		weatherData.setMeasurements(80, 65, 30.4f);
		weatherData.setMeasurements(82, 70, 29.2f);
		weatherData.setMeasurements(78, 90, 29.2f);
		
		weatherData.removeObserver(forecastDisplay);
		weatherData.setMeasurements(62, 90, 28.1f);
	}
}

publisher 通知 observer 更新数据,上面的做法是 publisher 主动将数据传递给 observer。

还有一种做法,publisher 通知 observers 的 update 函数中,不传入任何参数。Observer 得到通知后,主动调用 publisher 提供的接口 (getTemperature/getHumidity/getPressure) 从 publisher 获取想要的数据。