观察者模式

观察者模式有一个别名叫“发布-订阅模式”,或者说是“订阅-发布模式”,观察者(Observer)和被观察者(Subject)是联系在一起的,当观察目标发生改变时,逐个通知观察者。我们可以用报纸期刊的订阅来形象的说明,当你订阅了一份报纸,每天都会有一份最新的报纸送到你手上,有多少人订阅报纸,报社就会发多少份报纸,报社和订报纸的客户就是“一对多”的依赖关系。

image.png

简单的代码实现:

  1. // 报刊
  2. class Subject {
  3. constructor() {
  4. // 存放订阅者
  5. this.observers = [];
  6. }
  7. // 添加订阅者
  8. add(observer) {
  9. this.observers.push(observer);
  10. }
  11. // 新报纸
  12. updata(newMessage) {
  13. this.notify(newMessage);
  14. }
  15. // 通知订阅者
  16. notify(Message) {
  17. this.observers.forEach((observer) => {
  18. observer(Message);
  19. })
  20. }
  21. }
  22. // 定义订阅者A
  23. const observerA = (newspaper) => {
  24. console.log(newspaper + "——observerA");
  25. };
  26. // 定义订阅者B
  27. const observerB = (newspaper) => {
  28. console.log(msg + "——observerA");
  29. };
  30. var subject = new Subject();
  31. subject.add(observerA);
  32. subject.add(observerB);
  33. subject.updata("这是今天的报纸");
  34. //打印结果:
  35. // 这是今天的报纸——observerA
  36. // 这是今天的报纸——observerB

发布订阅模式

因为 Subject 就像一个发布者(Publisher),Subject 通知观察者(Observer)就像一个发布者通知他的订阅者(Subscriber)。经过时间的沉淀,发布订阅模式已经独立于观察者模式,成为另外一种不同的设计模式。

在现在的发布订阅模式中,称为发布者的消息发送者不会将消息直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件,称为调度中心或事件通道,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地分发它们给订阅者。

观察者模式与订阅-发布模式的区别 - 图2

举一个例子,你在微博上关注了 A,同时其他很多人也关注了 A,那么当 A 发布动态的时候,微博就会为你们推送这条动态。A 就是发布者,你是订阅者,微博就是调度中心,你和A是没有直接的消息往来的,全是通过微博来协调的(你的关注,A 的发布动态)。

简单的代码实现:

  1. // 微博
  2. class Broker {
  3. constructor() {
  4. // 存放关注者
  5. this.subscribers = [];
  6. }
  7. // 添加关注者
  8. on(subscriber) {
  9. this.subscribers.push(subscriber);
  10. }
  11. // 通知关注者
  12. notify(msg) {
  13. this.subscribers.forEach((subscriber) => {
  14. subscriber(msg);
  15. });
  16. }
  17. }
  18. // 被关注者A
  19. class Publisher {
  20. constructor(broker) {
  21. this.broker = broker;
  22. }
  23. // 发布动态
  24. emit(message) {
  25. this.broker.notify(message);
  26. }
  27. }
  28. // 定义关注者 A
  29. const subscriberA = (msg) => {
  30. console.log("关注者 A 收到一条动态:" + msg);
  31. };
  32. // 定义关注者 B
  33. const subscriberB = (msg) => {
  34. console.log("关注者 B 收到一条动态:" + msg);
  35. };
  36. const broker = new Broker();
  37. broker.on(subscriberA);
  38. broker.on(subscriberB);
  39. // 被关注者入驻微博
  40. const publisher = new Publisher(broker);
  41. publisher.emit("今天天气真好");
  42. //打印结果:
  43. // 关注者 A 收到一条动态:今天天气真好
  44. // 关注者 B 收到一条动态:今天天气真好

**

区别

用下图表示这两个模式最重要的区别:

观察者模式与订阅-发布模式的区别 - 图3

区别总结:

  • 观察者模式中,观察者是知道 Subject 的,Subject 一直保持对观察者进行记录。然而,在发布订阅模式中,发布者和订阅者不知道对方的存在。它们只有通过消息代理进行通信。
  • 发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。
  • 观察者模式大多数时候是同步的,比如当事件触发,Subject 就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的(使用消息队列)。
  • 观察者 模式需要在单个应用程序地址空间中实现,而发布-订阅更多的是跨应用程序模式。

优缺点

观察者模式
**

  • 优点:响应式,目标变化就会通知观察者,这是观察者最大的有点
  • 缺点:不灵活,相比订阅发布模式,由于目标和观察者是耦合在一起的,所以观察者模式需要同时引入目标和观察者才能达到响应式的效果。而订阅发布模式只需要引入事件中心,订阅者和发布者可以不在一处

订阅发布模式
**

  • 优点:
    • 灵活由于订阅发布模式的发布者和订阅者是解耦的,只要引入订阅发布模式的事件中心,无论在何处都可以发布订阅。同时订阅发布者相互之间不影响
    • 订阅发布模式在使用不当的情况下,容易造成数据流混乱,所以才有了 React 提出的单项数据流思想,就是为了解决数据流混乱的问题
  • 缺点:
    • 容易导致代码不好维护灵活是有点,同时也是缺点,使用不当就会造成数据流混乱,导致代码不好维护
    • 性能消耗更大订阅发布模式需要维护事件列队,订阅的事件越多,内存消耗越大

参考文章