01.观察者模式
1、认识观察者模式:
我们看看报纸和杂志的订阅是怎么回事:
(1)报社的业务就是出版报纸。
(2)向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,你就会一直收到新报纸。
(3) 当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来。
(4)只要报社还在运营,就会一直有人(或单位)向他们订阅报纸或者取消订阅报纸。
2、定义:
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
主题和观察者定义了一对多的关系。观察者依赖于此主题,只要主题状态一有变化,观察者就会被通知。根据通知的风格,观察者可能因此新值而更新。
实现观察者模式的方法不止一种,包含 Subject 和 Observer 接口的类最为常见。
C8CE0C4C-F581-445E-B2F4-_1_105_c.jpeg3、设计原则:
为了交互对象之间的松耦合设计而努力。
松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到最低。
因为任何时候我们都可以添加新的观察者,因为主题唯一依赖的东西是一个实现Observer接口的对象列表。
4、举例(气象站项目):
4.1 需求:
(1)该气象站必须建立在专利申请的 WeatherData 对象上,由 WeatherData 对象负责追踪目前的天气状况(温度、湿度、气压)。
(2)建立一个应用,有三种布告板(后面可能会有更多),分别显示目前的状态、气象统计和简单的预报(三种不同形式的展示)。当WeatherData 改变时,三种布告板必须实时更新。
4.2 设计:
008068C1-4A49-44AE-A02FFFCBDB_1_201_a.jpeg4.3 代码实现:
(1)观察者接口
/**
* 观察者接口
*
* 所有观察者都要实现此接口
*/
public interface Observer {
/**
* 当气象观察值改变时,主题会把这些状态值传给观察者
* @param temp
* @param humidity
* @param pressure
*/
public void update(float temp, float humidity, float pressure);
}
(2)主题接口
/**
* 主题接口
*
* 所有主题都要实现此接口
*/
public interface Subject {
/**
* 观察者注册接口
* @param o
*/
public void registerObserver(Observer o);
/**
* 观察者删除接口
* @param o
*/
public void removeObserver(Observer o);
/**
* 当主题状态改变时,通过这个方法告知所有的观察者
*/
public void notifyObservers();
}
(3)布告板接口
/**
* 布告板接口
*
* 所有布告板要实现此接口
*/
public interface DisplatElement {
/**
* 当布告板需要显示时,调用此方法
*/
public void display();
}
(4)主题实现类 - 天气数据
/**
* 天气数据
*
* 主题实现类
*/
public class WeatherData implements Subject {
/**
* 记录所有观察者
*/
private ArrayList observers;
/**
* 温度
*/
private float temperature;
/**
* 湿度
*/
private float humidity;
/**
* 气压
*/
private float pressure;
public WeatherData(ArrayList observers) {
this.observers = observers;
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
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(){
//TODO 检测是否达到通知条件,比如必须是温度等条件达到0.5的浮动再通知观察者
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;
measurementsChanged();
}
}
(5)三个布告板实现类,只有现实的属性不同。
public class CurrentConditionsDisplay implements Observer, DisplatElement {
/**
* 温度
*/
private float temperature;
/**
* 湿度
*/
private float humidity;
/**
* 主题
*/
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("CurrentConditionsDisplay【temperature:" + temperature + ";humidity:" + humidity+"】");
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
}
public class ForecastDisplay implements Observer, DisplatElement {
/**
* 湿度
*/
private float humidity;
/**
* 气压
*/
private float pressure;
/**
* 主题
*/
private Subject weatherData;
public ForecastDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("ForecastDisplay【humidity:" + humidity + ";pressure:" + pressure+"】");
}
@Override
public void update(float temp, float humidity, float pressure) {
this.pressure = pressure;
this.humidity = humidity;
display();
}
}
public class StatisticsDisplay implements Observer, DisplatElement {
/**
* 温度
*/
private float temperature;
/**
* 气压
*/
private float pressure;
/**
* 主题
*/
private Subject weatherData;
public StatisticsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("StatisticsDisplay【temperature:" + temperature + ";pressure:" + pressure+"】");
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.pressure = pressure;
display();
}
}
(6)测试类
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData(new ArrayList<Observer>());
CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
weatherData.setMeasurements(50,60,30f);
weatherData.setMeasurements(40,50,20f);
weatherData.setMeasurements(60,20,40f);
}
}
0308F50D-DD12-4D3C-8FD3-BBFCFD9A7962_1_201_a.jpeg
网友评论