观察者模式又叫做发布-订阅模式,属于行为型模式;观察者模式通过定义一种一对多得依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
观察者模式的UML类图如下:
如上图所示,观察者模式主要涉及到抽象主题角色、具体主题角色、抽象观察者角色、具体观察者角色等四种角色:
现在看天气预报已经成为我们生活中不可缺少的一个行为了。现在可以通过很多渠道查看到天气情况,如新浪天气,百度天气,微信公众号天气等,这些查看天气的都是从中国气象局公布的天气情况数据来的。在这以这个为例子讲解观察者模式。
例子的UML类图如下:
抽象观察者:
package com.charon.observer; /** * @className: Observer * @description: 抽象观察者 * @author: charon * @create: 2022-03-30 23:15 */ public interface Observer { /** * 更新天气情况 * @param temperature 气温 * @param pressure 气压 * @param humidity 湿度 */ void update(float temperature, float pressure, float humidity); }
具体观察者:
package com.charon.observer; /** * @className: CurrentConditions * @description: * @author: charon * @create: 2022-03-30 23:17 */ public class CurrentConditions implements Observer { /** * 气温,气压,湿度 */ private float temperature, pressure, humidity; @Override public void update(float temperature, float pressure, float humidity) { this.temperature = temperature; this.pressure = pressure; this.humidity = humidity; // 模拟展示 display(); } private void display() { System.out.println("当前的气温是:" + temperature); System.out.println("当前的气压是:" + pressure); System.out.println("当前的湿度是:" + humidity); } } package com.charon.observer; /** * @className: Baidu * @description: * @author: charon * @create: 2022-03-30 23:20 */ public class Baidu implements Observer{ /** * 气温,气压,湿度 */ private float temperature, pressure, humidity; @Override public void update(float temperature, float pressure, float humidity) { this.temperature = temperature; this.pressure = pressure; this.humidity = humidity; // 模拟展示 display(); } private void display() { System.out.println("百度天气查询得知,当前的气温是:" + temperature); System.out.println("百度天气查询得知,当前的气压是:" + pressure); System.out.println("百度天气查询得知,当前的湿度是:" + humidity); } }
抽象主题角色:
package com.charon.observer; /** * @className: Subject * @description: * @author: charon * @create: 2022-03-30 23:24 */ public interface Subject { /** * 注册一个观察者 * @param observer */ void registerObserver(Observer observer); /** * 删除一个观察者 * @param observer */ void removeObserver(Observer observer); /** * 通知观察者 */ void notifyObserver(); }
具体观察者角色:
package com.charon.observer; import java.util.ArrayList; import java.util.List; /** * @className: WeatherData * @description: * @author: charon * @create: 2022-03-30 23:27 */ public class WeatherData implements Subject{ private List<Observer> observers; /** * 气温,气压,湿度 */ private float temperature, pressure, humidity; public WeatherData() { this.observers = new ArrayList<>(); } public void setWeatherData(float temperature, float pressure, float humidity) { this.temperature = temperature; this.pressure = pressure; this.humidity = humidity; // 模拟展示 notifyObserver(); } @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 notifyObserver() { observers.forEach(item -> { item.update(this.temperature,this.pressure,this.humidity); }); } }
client:
package com.charon.observer; /** * @className: Client * @description: http://c.biancheng.net/view/1390.html * @author: charon * @create: 2022-03-30 22:56 */ public class Client { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); // 注册到具体观察者上 weatherData.registerObserver(new CurrentConditions()); weatherData.registerObserver(new Baidu()); weatherData.setWeatherData(10f,100f,30f); } } 打印: 当前的气温是:10.0 当前的气压是:100.0 当前的湿度是:30.0 百度天气查询得知,当前的气温是:10.0 百度天气查询得知,当前的气压是:100.0 百度天气查询得知,当前的湿度是:30.0
如上图的代码所示,观察者模式的例子就完成了,如果现在需要添加一个新浪天气的厂商,那么之需要让新浪天气实现Observer接口,然后注册到weatherData上就行了。
package com.charon.observer; /** * @className: sina * @description: * @author: charon * @create: 2022-03-30 23:20 */ public class sina implements Observer{ /** * 气温,气压,湿度 */ private float temperature, pressure, humidity; @Override public void update(float temperature, float pressure, float humidity) { this.temperature = temperature; this.pressure = pressure; this.humidity = humidity; // 模拟展示 display(); } private void display() { System.out.println("新浪天气查询得知,当前的气温是:" + temperature); System.out.println("新浪天气查询得知,当前的气压是:" + pressure); System.out.println("新浪天气查询得知,当前的湿度是:" + humidity); } }
观察者模式的主要优点如下:
观察者模式的主要缺点如下:
在软件系统中,当系统一方行为依赖另一方行为的变动时,可使用观察者模式松耦合联动双方,使得一方的变动可以通知到感兴趣的另一方对象,从而让另一方对象对此做出响应。
观察者模式适合以下几种情形: