首页 > 应用开发 > Java > 《Head First 设计模式》:观察者模式
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
要点:
主题父类/接口主要提供了注册观察者、移除观察者、通知观察者三个方法。
/**
* 主题
*/public class Subject {
/**
* 观察者列表
*/
private ArrayList<Observer> observers;
public Subject() {
observers = new ArrayList<>();
} /**
* 注册观察者
*/
public void registerObserver(Observer o) {
observers.add(o);
} /**
* 移除观察者
*/
public void removeObserver(Observer o) {
observers.remove(o);
} /**
* 通知所有观察者,并推送数据(也可以不推送数据,而是由观察者过来拉取数据)
*/
public void notifyObservers(Object data) { for (Observer o : observers) {
o.update(data);
}
}
}
观察者接口主要提供了更新方法,以供主题通知观察者时调用。
/**
* 观察者接口
*/public interface Observer { /**
* 根据主题推送的数据进行更新操作
*/
public void update(Object data);
}
/**
* 主题A
*/public class SubjectA extends Subject {
/**
* 主题数据
*/
private String data;
public String getData() { return data;
}
public void setData(String data) { this.data = data; // 数据发生变化时,通知观察者
notifyObservers(data);
}
}
通过观察者类的构造函数,注册成为主题的观察者。
/**
* 观察者A
*/public class ObserverImplA implements Observer { private Subject subject;
public ObserverImplA(Subject subject) { // 保存主题引用,以便后续取消注册
this.subject = subject; // 注册观察者
subject.registerObserver(this);
}
@Override
public void update(Object data) {
System.out.println("Observer A:" + data.toString());
}
}
/**
* 观察者B
*/public class ObserverImplB implements Observer { private Subject subject;
public ObserverImplB(Subject subject) { // 保存主题引用,以便后续取消注册
this.subject = subject; // 注册观察者
subject.registerObserver(this);
}
@Override
public void update(Object data) {
System.out.println("Observer B:" + data.toString());
}
}
public class Test {
public static void main(String[] args) { // 主题
SubjectA subject = new SubjectA(); // 观察者A
ObserverImplA observerA = new ObserverImplA(subject); // 观察者B
ObserverImplB observerB = new ObserverImplB(subject); // 模拟主题数据变化
subject.setData("I'm Batman!!!");
subject.setData("Why so serious...");
}
}
你的团队刚刚赢得一纸合约,负责建立 Weather-O-Rama 公司的下一代气象站——Internet 气象观测站。
该气象站建立在 WeatherData 对象上,由 WeatherData 对象负责追踪目前的天气状况(温度、湿度、气压)。并且具有三种布告板,分别显示目前的状况、气象统计以及简单的预报。当 WeatherData 对象获得最新的测量数据时,三种布告板必须实时更新。
并且,这是一个可扩展的气象站,Weather-O-Rama 气象站希望公布一组 API,好让其他开发人员可以写出自己的气象布告板,并插入此应用中。
/**
* 主题
*/public class Subject { /**
* 观察者列表
*/
private ArrayList<Observer> observers;
public Subject() {
observers = new ArrayList<>();
}
/**
* 注册观察者
*/
public void registerObserver(Observer o) {
observers.add(o);
} /**
* 移除观察者
*/
public void removeObserver(Observer o) {
observers.remove(o);
} /**
* 通知所有观察者,并推送数据
*/
public void notifyObservers(float temperature, float humidity, float pressure) { for (Observer o : observers) {
o.update(temperature, humidity, pressure);
}
}
}
/**
* 观察者接口
*/public interface Observer { /**
* 更新观测值
*/
public void update(float temperature, float humidity, float pressure);
}
/**
* 气象数据
*/public class WeatherData extends Subject {
/**
* 温度
*/
private float temperature; /**
* 湿度
*/
private float humidity; /**
* 气压
*/
private float pressure;
public void measurementsChanged() { // 观测值变化时,通知所有观察者
notifyObservers(temperature, humidity, pressure);
}
/**
* 设置观测值(模拟观测值变化)
*/
public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure;
measurementsChanged();
}
}
/**
* 目前状态布告板
*/public class CurrentConditionsDisplay implements Observer {
private Subject weatherData; private float temperature; private float humidity;
public CurrentConditionsDisplay(Subject weatherData) { this.weatherData = weatherData; // 注册观察者
weatherData.registerObserver(this);
} @Override
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 degress and " + humidity + "% humidity");
}
}
/**
* 统计布告板
*/public class StatisticsDisplay implements Observer { private Subject weatherData; private ArrayList<Float> historyTemperatures;
public StatisticsDisplay(Subject weatherData) { this.weatherData = weatherData; // 注册观察者
weatherData.registerObserver(this);
historyTemperatures = new ArrayList<>();
}
@Override public void update(float temperature, float humidity, float pressure) { this.historyTemperatures.add(temperature);
display();
}
public void display() { if (historyTemperatures.isEmpty()) { return;
}
Collections.sort(historyTemperatures); float avgTemperature = 0; float maxTemperature = historyTemperatures.get(historyTemperatures.size() - 1); float minTemperature = historyTemperatures.get(0); float totalTemperature = 0; for (Float temperature : historyTemperatures) {
totalTemperature += temperature;
}
avgTemperature = totalTemperature / historyTemperatures.size();
System.out.println("Avg/Max/Min temperature:" + avgTemperature + "/" + maxTemperature + "/" + minTemperature);
}
}
/**
* 预测布告板
*/public class ForecastDisplay implements Observer { private Subject weatherData; private float temperature; private float humidity; private float pressure;
public ForecastDisplay(Subject weatherData) { this.weatherData = weatherData; // 注册观察者
weatherData.registerObserver(this);
} @Override
public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure;
display();
}
public void display() {
System.out.println("Forecast:waiting for implementation...");
}
}
public class Test {
public static void main(String[] args) { // 气象数据
WeatherData weatherData = new WeatherData(); // 目前状态布告板
CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData); // 统计布告板
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); // 预测布告板
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
// 模拟气象观测值变化
weatherData.setMeasurements(80, 65, 30.4F);
weatherData.setMeasurements(82, 70, 29.2F);
weatherData.setMeasurements(78, 90, 29.2F);
}
}
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69973017/viewspace-2722126/ ,如需转载,请注明出处,否则将追究法律责任。