设计模式之观察者模式
用过微信公众号的人都知道,当发布者发布一篇推文的时候,所有订阅者都会接收到订阅消息。基于这个应用场景,我们今天来聊聊设计模式中的
观察者模式
。
介绍
观察者模式(也称发布-订阅模式)是一种行为型设计模式。该模式定义了一对多的依赖关系,发布者为一,订阅者为多。当发布者有消息改变时会推送更新数据,订阅者作为观察者感知消息的改变并实时改变自己的消息集。
观察者模式UML类图
在观察者模式中有如下角色:
- Subject:抽象主题,为具体主题定义接口规范,每个主题都可以有任意数量的观察者,抽象主题提供了一个接口,可以增加和删除观察者对象。
- WeatherData:具体主题,实现抽象主题方法。其中该主题类聚合了观察者。在抽象主题内部有数据变化时会分别为注册过的观察者推送更新数据。
- Observer:抽象观察者,为具体观察者定义了操作接口规范,其中一个最重要的方法就是更新数据的方法(update)。使得当主题发生更新变化时更新自己。
- CurrentCondition:具体观察者,实现抽象观察者的接口规范。
观察者模式的简单代码实现
抽象主题接口(Subject):
1package com.atguigu.look;
2
3public interface Subject {
4
5 /**
6 * 注册接口
7 */
8 void registerObserver(Observer observer);
9
10 /**
11 * 用户移除接口
12 */
13 void removeObserver(Observer observer);
14
15 /**
16 * 更新接口
17 */
18 void notifyObserver();
19
20}
具体主题类(WeatherData)实现抽象主题接口:
1package com.atguigu.look;
2
3import java.util.ArrayList;
4import java.util.List;
5
6public class WeatherData implements Subject {
7 /**
8 * 温度
9 */
10 private float temperature;
11 /**
12 * 气压
13 */
14 private float pressure;
15 /**
16 * 湿度
17 */
18 private float humidity;
19 /**
20 * 订阅者列表
21 */
22 private List<Observer> observers;
23
24 public WeatherData() {
25 this.observers = new ArrayList();
26 }
27
28 public float getTemperature() {
29 return temperature;
30 }
31
32 public void setTemperature(float temperature) {
33 this.temperature = temperature;
34 }
35
36 public float getPressure() {
37 return pressure;
38 }
39
40 public void setPressure(float pressure) {
41 this.pressure = pressure;
42 }
43
44 public float getHumidity() {
45 return humidity;
46 }
47
48 public void setHumidity(float humidity) {
49 this.humidity = humidity;
50 }
51
52 public List<Observer> getObservers() {
53 return observers;
54 }
55
56 public void setObservers(List<Observer> observers) {
57 this.observers = observers;
58 }
59
60 public void dataChange() {
61 notifyObserver();
62 }
63
64 public void setData(float temperature, float pressure, float humidity) {
65 this.temperature = temperature;
66 this.pressure = pressure;
67 this.humidity = humidity;
68 dataChange();
69 }
70
71 @Override
72 public void registerObserver(Observer observer) {
73 this.observers.add(observer);
74 }
75
76 @Override
77 public void removeObserver(Observer observer) {
78 if (this.observers.contains(observer)) {
79 this.observers.remove(observer);
80 }
81 }
82
83 @Override
84 public void notifyObserver() {
85 for (int i = 0; i < this.observers.size(); i++) {
86 this.observers.get(i).update(this.temperature, this.pressure, this.humidity);
87 }
88 }
89}
抽象观察者接口(Observer):
1package com.atguigu.look;
2
3public interface Observer {
4
5 /**
6 * 数据更新接口
7 */
8 void update(float temperature, float pressure, float humidity);
9}
具体观察者接口(CurrentConditions)实现抽象观察者接口:
1package com.atguigu.look;
2
3public class CurrentConditions implements Observer {
4
5 /**
6 * 温度
7 */
8 private float temperature;
9 /**
10 * 气压
11 */
12 private float pressure;
13 /**
14 * 湿度
15 */
16 private float humidity;
17
18 @Override
19 public void update(float temperature, float pressure, float humidity) {
20 this.temperature = temperature;
21 this.pressure = pressure;
22 this.humidity = humidity;
23 display();
24 }
25
26 // 信息展示
27 public void display() {
28 System.out.println("***CurrentConditions temperature-->" + this.temperature + "***");
29 System.out.println("***CurrentConditions pressure-->" + this.pressure + "***");
30 System.out.println("***CurrentConditions humidity-->" + this.humidity + "***");
31 }
32}
编写主类(Client)测试观察者模式:
1package com.atguigu.look;
2
3public class Client {
4 public static void main(String[] args) {
5 WeatherData weatherData = new WeatherData();
6 CurrentConditions currentConditions = new CurrentConditions();
7 weatherData.registerObserver(currentConditions);
8 weatherData.setData(23f, 23f, 23f);
9 }
10}/*Output:
11***CurrentConditions temperature-->23.0***
12***CurrentConditions pressure-->23.0***
13***CurrentConditions humidity-->23.0***
14*//~
根据类图,我只实现了其中一个具体观察者,感兴趣的小伙伴可以在我代码的基础上实现哦,你会发现根本不需要修改我的代码即能实现扩展,这也正符合我们设计模式中的ocp原则(对扩展开放,对修改关闭)
.
观察者模式的优缺点
优点
- 解除耦合,让耦合的双方都依赖于抽象,从而使得各自的变换都不会影响另一边的变换
缺点
- 在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现
JDK源码剖析
观察者模式在我们JDK中有没有被应用上呢?答案是肯定的,下面我们来看看JDK中是如何运用观察者模式
的。
我们来看看JDK中的类图:
再看看我们上面实践所画的类图:
对比可以看出有天然的相似性,唯一的不同之处就是JDK中没有主题抽象类,但并不是说没有主题抽象类就不是
观察者模式
了,设计模式是思想而不是代码,我们要明白这一点,只要思想跟
观察者模式
差不多,我们就可以说它是使用了
观察者模式`,我们在学习的过程中要注意这一点。
设计模式之观察者模式`今天就谈论到这里,祝大家学习愉快~