一、观察者模式
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖着都会收到通知并自动更新。
举个例子,其实就是报纸订阅服务,出版者和订阅者的关系。出版者一旦有了新的报纸,就去通知订阅者“最新的报纸已经到了”,你可以这么理解。
出版者就是主题,订阅者就是观察者。
二、举例
设计一个气象站,要求如下
- 气象站一旦接受到新的气象信息,就马上通知它的订阅者
- 订阅者收到信息之后,马上将信息展示在布告板上
自定义观察者模式
主题类接口
package com.jackeys.ObserverMode.DIY;
/**
* @Description: 主题类接口
* @ClassName: Subject
* @Package com.jackeys.ObserverMode
* @Author: Jackeys 1623427047@qq.com
* @Copyright 版权归Jackeys企业(或个人)所有
* @CreateTime: 2021/10/6 11:48
* @Version: 1.0
*/
public interface Subject {
/**
* 用来注册观察者
* @param observer 观察者
*/
void registerObserver(Observer observer);
/**
* 用来删除观察者
* @param observer 观察者
*/
void removeObserver(Observer observer);
/**
* 当主题改变时,通知所有观察者
*/
void notifyObservers();
}
主题接口实现类
package com.jackeys.ObserverMode.DIY;
import java.util.ArrayList;
/**
* @Description: 主题接口实现类
* @ClassName: WeatherData
* @Package com.jackeys.ObserverMode
* @Author: Jackeys 1623427047@qq.com
* @Copyright 版权归Jackeys企业(或个人)所有
* @CreateTime: 2021/10/6 11:58
* @Version: 1.0
*/
public class WeatherData implements Subject {
private ArrayList<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
this.observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
this.observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
int index = observers.indexOf(observer);
if (index >= 0) {
this.observers.remove(index);
}
}
/**
* 通知所有观察者
*/
@Override
public void notifyObservers() {
for(int i=0;i<this.observers.size();i++){
this.observers.get(i).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();
}
}
观察者接口
package com.jackeys.ObserverMode.DIY;
/**
* @Description: 观察者类接口
* @ClassName: Observer
* @Package com.jackeys.ObserverMode
* @Author: Jackeys 1623427047@qq.com
* @Copyright 版权归Jackeys企业(或个人)所有
* @CreateTime: 2021/10/6 11:49
* @Version: 1.0
*/
public interface Observer {
/**
* 改变时,将数据传给所有的观察者
* @param temp 温度
* @param humidity 湿度
* @param pressure 气压
*/
void update(float temp,float humidity,float pressure);
}
观察者接口实现类
package com.jackeys.ObserverMode.DIY;
/**
* @Description: 布告板类
* @ClassName: CurrentConditionsDisplay
* @Package com.jackeys.ObserverMode
* @Author: Jackeys 1623427047@qq.com
* @Copyright 版权归Jackeys企业(或个人)所有
* @CreateTime: 2021/10/6 12:07
* @Version: 1.0
*/
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private float pressure;
private Subject weatherData;
/**
* 放入主题
* @param weatherData
*/
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
/**
* 显示气象信息
*/
@Override
public void display() {
System.out.println("现在的天气:温度 "+this.temperature+",湿度 "+this.humidity+",气压 "+this.pressure);
}
/**
* 改变气象信息
* @param temp 温度
* @param humidity 湿度
* @param pressure 气压
*/
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature=temp;
this.humidity=humidity;
this.pressure=pressure;
this.display();
}
}
布告板接口
package com.jackeys.ObserverMode.DIY;
/**
* @Description: 显示类接口
* @ClassName: DisplayElement
* @Package com.jackeys.ObserverMode
* @Author: Jackeys 1623427047@qq.com
* @Copyright 版权归Jackeys企业(或个人)所有
* @CreateTime: 2021/10/6 11:55
* @Version: 1.0
*/
public interface DisplayElement {
/**
* 用来显示温度、湿度、气压
*/
void display();
}
测试
package com.jackeys.ObserverMode.DIY;
/**
* @Description: 测试观察者模式
* @ClassName: Test
* @Package com.jackeys.ObserverMode
* @Author: Jackeys 1623427047@qq.com
* @Copyright 版权归Jackeys企业(或个人)所有
* @CreateTime: 2021/10/6 12:13
* @Version: 1.0
*/
public class Test {
public static void main(String[] args) {
WeatherData weatherData=new WeatherData();
CurrentConditionsDisplay currentConditionsDisplay=new CurrentConditionsDisplay(weatherData);
CurrentConditionsDisplay currentConditionsDisplay1=new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(1.1f,1.2f,1.3f);
}
}
输出
Java内置观察者模式
布告板接口
package com.jackeys.ObserverMode.JavaInner;
/**
* @Description: 显示类接口
* @ClassName: DisplayElement
* @Package com.jackeys.ObserverMode
* @Author: Jackeys 1623427047@qq.com
* @Copyright 版权归Jackeys企业(或个人)所有
* @CreateTime: 2021/10/6 11:55
* @Version: 1.0
*/
public interface DisplayElement {
/**
* 用来显示温度、湿度、气压
*/
void display();
}
主题类
package com.jackeys.ObserverMode.JavaInner;
import java.util.Observable;
/**
* @Description: 主题类
* @ClassName: WeatherData
* @Package com.jackeys.ObserverMode.JavaInner
* @Author: Jackeys 1623427047@qq.com
* @Copyright 版权归Jackeys企业(或个人)所有
* @CreateTime: 2021/10/6 13:02
* @Version: 1.0
*/
public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
public void measurementsChanged(){
setChanged();
notifyObservers();//没有这一步表示观察者拉去信息,而不是推送
}
public void setMeasurements(float temperature,float humidity,float pressure){
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
this.measurementsChanged();
}
//观察者可以通过以下方式拉去信息
public float getPressure() {
return this.pressure;
}
public float getHumidity() {
return this.humidity;
}
public float getTemperature() {
return this.temperature;
}
}
观察者类
package com.jackeys.ObserverMode.JavaInner;
import java.util.Observable;
import java.util.Observer;
/**
* @Description: 观察者类
* @ClassName: CurrentConditionsDisplay
* @Package com.jackeys.ObserverMode.JavaInner
* @Author: Jackeys 1623427047@qq.com
* @Copyright 版权归Jackeys企业(或个人)所有
* @CreateTime: 2021/10/6 13:08
* @Version: 1.0
*/
public class CurrentConditionsDisplay implements Observer,DisplayElement {
private float temperature;
private float humidity;
private float pressure;
private Observable observable;
public CurrentConditionsDisplay(Observable observable){
this.observable=observable;
observable.addObserver(this);
}
@Override
public void display() {
System.out.println("现在的天气:温度 "+this.temperature+",湿度 "+this.humidity+",气压 "+this.pressure);
}
@Override
public void update(Observable o, Object arg) {
if(o instanceof WeatherData){
WeatherData weatherData=(WeatherData) o;
this.temperature=weatherData.getTemperature();
this.humidity=weatherData.getHumidity();
this.pressure=weatherData.getPressure();
display();
}
}
}
测试
package com.jackeys.ObserverMode.JavaInner;
/**
* @Description: 测试Java内置的观察者模式
* @ClassName: Test
* @Package com.jackeys.ObserverMode.JavaInner
* @Author: Jackeys 1623427047@qq.com
* @Copyright 版权归Jackeys企业(或个人)所有
* @CreateTime: 2021/10/6 13:14
* @Version: 1.0
*/
public class Test {
public static void main(String[] args) {
WeatherData weatherData=new WeatherData();
CurrentConditionsDisplay currentConditionsDisplay=new CurrentConditionsDisplay(weatherData);
CurrentConditionsDisplay currentConditionsDisplay1=new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(1.2f,1.3f,1.4f);
}
}
输出