【设计模式】观察者模式
一、简介
观察者模式(发布/订阅模式),定义了对象之间一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
有很多项目都用到了该设计模式,比如Spring的事件机制、消息队列等。
Java提供了两个接口java.util.Observable和java.util.Observer,也可以利用这两个接口实现。
类图如下:

观察者模式类图
二、示例
需求背景是气象站发布天气数据,所有订阅了气象站的布告板显示天气数据。
先上类图:

enter description here
主题接口
/** * 主题接口 * Created by 2YSP on 2018/1/24. */ public interface Subject { /** * 注册一个观察者 * @param observer */ void registerObserver(Observer observer); /** * 移除一个观察者 * @param observer */ void removeObserver(Observer observer); /** * 通知所有观察者 */ void notifyObservers(); }
观察者接口
public interface Observer { /** * 所有观察者必须实现该方法, * 当气象观测值改变时,主题会把这些状态值当参数传给观察者 * @param temp * @param humidity * @param pressure */ void update(float temp,float humidity,float pressure); }
具体主题WeatherData
public class WeatherData implements Subject { /** * 注册的观察者集合 */ private List<Observer> observers; /** * 温度 */ private float temperature; /** * 湿度 */ private float humidity; /** * 气压 */ private float pressure; public WeatherData(){ observers = new ArrayList(); } @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { if (observers.contains(observer)){ observers.remove(observer); } } @Override public void notifyObservers() { observers.forEach(o -> { o.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(); } //WeatherData的其他方法 }
当前状况布告板,这里只弄了一个,还可以根据自己的需求定义其他种类的布告板。
/** * 当前状况布告板(还可以建立其他观察者) * Created by 2YSP on 2018/1/24. */ public class CurrentConditionDisplay implements Observer,DisplayElement { /** * 温度 */ private float temperature; /** * 湿度 */ private float humidity; private Subject weatherData; public CurrentConditionDisplay(Subject weatherData){ this.weatherData = weatherData; weatherData.registerObserver(this); } @Override public void display() { System.out.println("Current conditions: "+temperature+"F degrees and "+humidity+"% humidity"); } @Override public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; display(); } }
DisplayElement
public interface DisplayElement { /** * 布告板显示气象数据 */ void display(); }
气象站
public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionDisplay currentCondition = new CurrentConditionDisplay(weatherData); weatherData.setMeasurements(80,65,30.4f); } }
运行main方法控制台输出如下,说明布告板收到了消息并自动更新。
Current conditions: 80.0F degrees and 65.0% humidity
注意: 这里是通过构造方法传入具体主题,然后调用具体主题的registerObserver(Observer observer) 方法来实现注册观察者的。在实际项目中,我们可以通过在spring的xml配置文件上配置进行观察者的注册,这样更加灵活,不用修改代码。需要给WeatherData添加一个setObservers(List observers) 方法,利用set方法注入。
<bean id="weatherData" class="xx.xx.WeatherData"> <property name="observers"> <list> <ref bean="currentConditionDisplay"/> </list> </property> </bean>
本文作者:烟味i
本文链接:https://www.cnblogs.com/2YSP/p/11602078.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步