定义
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.
观察者模式定义了对象之间的一对多依赖关系,这样当一个对象改变状态时,依赖它的所有对象都会被通知并自动更新该状态。
具体实现时,ConcreteSubject包含一个Observer对象的List列表,通过该列表实现注册、注销和通知观察者的方法。ConcreteObserver包含一个Subject对象,用于将自己注册到该Subject。
实例:天气预报
三个接口:
public interface Subject {
void registerObserver(Observer o);
void removObserver(Observer o);
void notifyObservers();
}
public interface Observer {
void update(float temp,float humidity, float pressure);
}
public interface DisplayElement {
void display();
}
WeatherData类:
public class WeatherData implements Subject {
private List<Observer> observers;//观察者列表
private float temperature;//温度
private float humidity;//湿度
private float pressure;//气压
public WeatherData() {
observers = new ArrayList<>(10);
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(i);
}
}
@Override
public void notifyObservers() {
for (Observer o : observers) {
o.update(this.temperature, this.humidity, this.pressure);
}
}
/**
* 测量改变方法,应该在每一次重新测量后调用,通知观察者数据变化
*/
public void measurementsChanged() {
this.notifyObservers();
}
/**
* 模拟测量方法,即设置温度,湿度和气压的最新测量值,并调用测量改变方法
* @param temperature
* @param humidity
* @param pressure
*/
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
this.measurementsChanged();
}
}
天气展示类:
public class CurrentConditionsDisplay implements Observer ,DisplayElement {
private float temperature;
private float humidity;
private float pressure;
private Subject weatherData;//要观察的对象
/**
* 构造对象时,将自己注册到Subject
* @param weatherData
*/
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);//注册自己
}
@Override
public void display() {
System.out.println(this.toString());
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature=temp;
this.humidity=humidity;
this.pressure=pressure;
display();
}
@Override
public String toString() {
return "CurrentConditionsDisplay{" +
"temperature=" + temperature +
", humidity=" + humidity +
", pressure=" + pressure +
'}';
}
}
测试类:
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData=new WeatherData();
DisplayElement currentConditionsDisplay=new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(80,65,30.4f);
weatherData.setMeasurements(82,70,29.4f);
}
}
Java中的实现
JDK中实现了观察者模式,有Observable类和Observer接口组成。前者是类,后者是接口,说明主要实现思想体现在Observable,而具体的业务逻辑则实现Observer接口的update方法。
import java.util.Observable;
public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
public void measurementsChanged() {
setChanged();//标记为已改变
notifyObservers();//该方法会调用所有观察者的updae方法,并清除changed的状态
}
/**
* 模拟测量方法,即设置温度,湿度和气压的最新测量值,并调用测量改变方法
*/
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
this.measurementsChanged();
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public float getPressure() {
return pressure;
}
}
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private float pressure;
private Observable observable;//要观察的对象
/**
* 构造对象时,将自己注册到Observable
*
* @param observable
*/
public CurrentConditionsDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);//注册自己
}
@Override
public void display() {
System.out.println(this.toString());
}
@Override
public void update(Observable obs, Object arg) {
if (obs instanceof WeatherData) {
WeatherData weatherData = (WeatherData) obs;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
this.pressure = weatherData.getPressure();
display();
}
}
@Override
public String toString() {
return "CurrentConditionsDisplay{" +
"temperature=" + temperature +
", humidity=" + humidity +
", pressure=" + pressure +
'}';
}
}