一文弄懂设计模式之观察者模式、发布订阅模式

前言

hello,大家好!我是图图酱,今天就和大家分享一下设计模式里的观察者模式发布订阅模式,很多人对于这两种设计模式的概念可能有点模糊分不清,有的觉得这两种模式其实是一样的。其实这两种确实很类似但是略有区别,下面就通过简单的实现带大家弄懂这两种模式的区别及用法。

观察者&发布订阅

首先通过上图我们可以清楚的看到两者的区别。

  • 观察者模式是通过观察者(Observer)直接对目标(Subject)进行订阅(Subscribe),事件通知也是由目标直接通知观察者,两者直接是直接关联的。
  • 发布订阅模式在观察者模式之前多了一个时间时间调度中心(Event Channel),订阅者(Subscriber)和发布者(Publisher)不是直接关联的,两者直接的消息传递需要经过调度中心来进行,这样的好处就是做到了松散解耦,更为灵活。

Linus Torvalds --- 'Talk is cheap . Show me the code.'

观察者模式

js 复制代码
// 定义一个目标对象
class Subject {
  constructor() {
    this.Observers = [];
  }
  
  add(observer) {
    //添加
    this.Observers.push(observer);
  }
  
  remove(observer) {
    //移除
    this.Observers.filter((item) => item === observer);
  }
  
  notify() {
    //通知所有观察者
    this.Observers.forEach((item) => {
      item.update();
    });
  }
}

//定义观察者对象
class Observer {
  constructor(name) {
    this.name = name;
  }
  
  update() {
    console.log(`my name is:${this.name}`);
  }
}

// 实例化目标对象
let sub = new Subject();

let obs1 = new Observer("observer11");
let obs2 = new Observer("observer22");

sub.add(obs1);
sub.add(obs2);

sub.notify();

观察者模式由目标(Subject)维护对应的观察者对象(Observer),在需要通知时再由目标去通知其维护的观察者对象,主要的调度工作都在观察者这里

发布订阅模式

js 复制代码
// 事件中心
class Events {
  // 订阅者列表
  events = {};

  // 订阅
  subscribe(key, fn) {
    if (!Array.isArray(this.subscriber[key])) {
      this.subscriber[key] = [];
    }
    this.subscriber[key].push(fn);
  }

  // 取消单个订阅
  unsubscribe(key, fn) {
    const subscribers = this.subscriber[key] || [];
    this.subscriber[key] = subscribers.filter((_fn) => _fn !== fn);
  }

  // 取消所有订阅
  unsubscribeAll(key) {
    this.subscriber[key] = [];
  }

  // 发布
  publish(key, ...args) {
    const subscribers = this.subscriber[key] || [];

    if (subscribers.length === 0) {
      console.log("has't subscriber");
    }

    subscribers.forEach((subscriber) => {
      subscriber.apply(this, args);
    });
  }
}

// 创建发布订阅信道中介
const e = new Events();

// 发布者
const publisher = {
  article1: 'article1',
  article2: 'article2',
};

// 订阅者
const subscriber1 = (article) => {
  console.log(`sub1 receive ${article}`);
};
const subscriber2 = (article) => {
  console.log(`sub2 receive ${article}`);
};

// 订阅操作
e.subscribe('event1', subscriber1);
e.subscribe('event1', subscriber2);

// 发布操作
e.publish('event1', publisher.article1);
// sub1 receive article1
// sub2 receive article1

// 多事件发布订阅
e.subscribe('event2', subscriber1);
e.publish('event2', publisher.article1);
// sub1 receive article1

// 取消单个订阅
e.unsubscribe('event1', subscriber1);
e.publish('event1', publisher.article2);
// sub2 receive article2

// 取消所有订阅
e.unsubscribeAll('event1');
e.publish('event1');
//  has't subscriber

发布订阅模式有一个单独的调度中心(Events),它在这里负责了在观察者模式里由观察者(Observer)维护的调度工作,这样订阅者(Subscriber)发布者(Publisher)就变得纯粹,发布者只需要发布事件,订阅者做好接到响应需要的回调。

小结

  1. 可以理解为观察者模式里,目标(Subject)维护了一个观察者(Observer)列表,[obs1, obs2],在发布时通知这个观察者列表里的观察者,发布订阅里,事件中心(Events)维护的是个{event1: [sub1, sub2], event2: [sub1, sub3]}事件对象
  2. 观察者模式由具体目标(Subject)调度,发布订阅模式由调度中心(Events)统一调度,发布订阅模式比观察者模式多一个调度中心
  3. 发布订阅模式中,组件是松散耦合的,观察者模式相反。

ok👌,到这里,大家是不是对于这两种设计模式有了清晰的了解了呢😉,以上是个人对于这两个设计模式的理解,如有错误请多指教🫡

参考

  1. www.patterns.dev/posts/obser...
  2. juejin.cn/post/684490...
  3. juejin.cn/post/727788...
相关推荐
masa01025 分钟前
JavaScript--JavaScript基础
开发语言·javascript
她似晚风般温柔7897 小时前
Uniapp + Vue3 + Vite +Uview + Pinia 分商家实现购物车功能(最新附源码保姆级)
开发语言·javascript·uni-app
Jiaberrr8 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy8 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
Ylucius9 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
200不是二百9 小时前
Vuex详解
前端·javascript·vue.js
LvManBa9 小时前
Vue学习记录之三(ref全家桶)
javascript·vue.js·学习
深情废杨杨9 小时前
前端vue-父传子
前端·javascript·vue.js
司篂篂11 小时前
axios二次封装
前端·javascript·vue.js
姚*鸿的博客11 小时前
pinia在vue3中的使用
前端·javascript·vue.js