设计模式 - 观察者模式
目录
- 认识观察者模式
- 定义观察者模式
- 观察者模式类图
- 案例:实现气象站(推)
- Java内置的观察者模式
- 案例:利用内置重新实现实现气象站(拉)
认识观察者模式
我们看看报纸和杂志的订阅是怎么回事
- 报社的业务就是出版报纸;
- 向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,你就会一直收到新报纸;
- 当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来;
- 只要报社还在运营,就会一直有人向他们订阅报纸或取消订阅报纸;
出版者 + 订阅者 = 观察者模式
定义观察者模式
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
观察者模式类图
案例:实现气象站(推)
主题接口
/**
* 主题
*/
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
观察者接口
/**
* 观察者
*/
public interface Observer {
void update(float temp, float humidity, float pressure);
}
布告板接口
/**
* 布告板
*/
public interface DisplayElement {
public void display();
}
气象数据接收器(实现主题)
public class WeatherData implements Subject{
private ArrayList<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
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 class CurrentConditionsDisplay implements Observer, DisplayElement{
private float temperature;
private float humidity;
private Subject weatherData;
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();
}
@Override
public void display() {
System.out.println("目前状况布告板: " + temperature + "摄氏度 " + humidity + "%湿度");
}
}
测试类
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(20, 65, 30.4f);
weatherData.setMeasurements(18, 70, 29.2f);
weatherData.setMeasurements(12, 90, 29.2f);
}
}
Java内置的观察者模式
java.util 包中有 Observer 接口和 Observable 类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O8gIgWM0-1644149256064)(\picture\Java内置的观察者模式.png)]
案例:利用内置重新实现实现气象站(拉)
气象数据接收器(继承 Observable类)
import java.util.Observable;
public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
}
public void measurementsChanged() {
setChanged();
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();
}
目前状况布告板(实现观察者和布告板)
import java.util.Observable;
import java.util.Observer;
public class CurrentConditionsDisplay implements Observer, DisplayElement {
Observable observable;
private float temperature;
private float humidity;
public CurrentConditionsDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
// 把主题传给观察者,让观察者主动拉取数据
@Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherData) {
WeatherData weatherData = (WeatherData) o;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
@Override
public void display() {
System.out.println("目前状况布告板: " + temperature + "摄氏度 " + humidity + "%湿度");
}
}
测试类
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(20, 65, 30.4f);
weatherData.setMeasurements(18, 70, 29.2f);
weatherData.setMeasurements(12, 90, 29.2f);
}
}