观察者模式vs发布订阅模式
观察者模式
所谓观察者模式,其实就是为了实现**松耦合 (loosely coupled)**。
用《Head First 设计模式》里的气象站为例子,每当气象测量数据有更新,changed()
方法就会被调用,于是我们可以在 changed()
方法里面,更新气象仪器上的数据,比如温度、气压等等。
但是这样写有个问题,就是如果以后我们想在 changed()
方法被调用时,更新更多的信息,比如说湿度,那就要去修改 changed()
方法的代码,这就是紧耦合的坏处。
怎么解决呢?使用观察者模式,面向接口编程,实现松耦合。
观察者模式里面,changed()
方法所在的实例对象,就是被观察者(Subject,或者叫 Observable),它只需维护一套观察者(Observer)的集合,这些 Observer 实现相同的接口,Subject 只需要知道,通知 Observer 时,需要调用哪个统一方法就好了:
实现
观察者模式使用三个类 Subject、Observer 和 Client。Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法。我们创建 Subject 类、Observer 抽象类和扩展了抽象类 Observer 的实体类。
ObserverPatternDemo,我们的演示类使用 Subject 和实体类对象来演示观察者模式。
步骤 1
创建 Subject 类。
1 | import java.util.ArrayList; |
步骤 2
创建 Observer 类。
1 | public abstract class Observer { |
步骤 3
创建实体观察者类。
1 | public class BinaryObserver extends Observer{ |
1 | public class OctalObserver extends Observer{ |
1 | public class HexaObserver extends Observer{ |
步骤 4
使用 Subject 和实体观察者对象。
1 | public class ObserverPatternDemo { |
步骤 5
执行程序,输出结果:
1 | First state change: 15 |
发布订阅模式
大概很多人都和我一样,觉得发布订阅模式里的 Publisher,就是观察者模式里的 Subject,而 Subscriber,就是 Observer。Publisher 变化时,就主动去通知 Subscriber。
其实并不是。
在发布订阅模式里,发布者,并不会直接通知订阅者,换句话说,发布者和订阅者,彼此互不相识。
互不相识?那他们之间如何交流?
答案是,通过第三者,也就是在消息队列里面,我们常说的经纪人 Broker。
发布者只需告诉 Broker,我要发的消息,topic 是 AAA;
订阅者只需告诉 Broker,我要订阅 topic 是 AAA 的消息;
于是,当 Broker 收到发布者发过来消息,并且 topic 是 AAA 时,就会把消息推送给订阅了 topic 是 AAA 的订阅者。当然也有可能是订阅者自己过来拉取,看具体实现。
区别
也就是说,发布订阅模式里,发布者和订阅者,不是松耦合,而是完全解耦的。
放一张极简的图,给大家对比一下这两个模式的区别:
总结
从表面上看:
- 观察者模式里,只有两个角色 —— 观察者 + 被观察者
- 而发布订阅模式里,却不仅仅只有发布者和订阅者两个角色,还有一个经常被我们忽略的 —— 经纪人 Broker
往更深层次讲:
- 观察者和被观察者,是松耦合的关系
- 发布者和订阅者,则完全不存在耦合
从使用层面上讲:
- 观察者模式,多用于单个应用内部
- 发布订阅模式,则更多的是一种跨应用的模式 (cross-application pattern),比如我们常用的消息中间件