订阅-发布模式

181 阅读1分钟

第一版

// 发布者类
class Publisher {
  constructor(){
  	this.subs = []
  }
  
  // 消息订阅
  addSub(...subs) {
    subs.forEach(sub => {
      this.subs.push(sub)
  	})
  }
      
  
  // 消息发布
  notify() {
    this.subs.forEach( sub => {
    	sub.update()
    })
  }
  
}

// 创建发布者
const p = new Publisher();

// 创建订阅者
const s1 = {
  name: 's1',
  update(){
    console.log(`I am ${this.name}`)
  }
}

const s2 = {
  name: 's2',
  update(){
    console.log(`I am ${this.name}`)
  }
}

const s3 = {
  name: 's3',
  update(){
    console.log(`I am ${this.name}`)
  }
}


// 订阅者订阅发布者
p.addSub(s1,s2,s3);

// 发布者发布消息
p.notify()

// 输出结果
I am s1
I am s2
I am s3

这样就实现了一个最简单的订阅发布模型,订阅者订阅了发布者之后,不需要实时观察发布者的变化,一旦发布者有任何的变化,就会通知所有订阅了它的订阅者们,类似于微信公众号,我们订阅了某个微信公众号,并不需要一直去看该订阅号有没有更新,因为一旦该订阅号更新了,就会向所有订阅了它的用户们发出通知,订阅者们自然也就收到了订阅号的发布。

第二版、增加参数

// 发布者类
class Publisher {
  constructor() {
    this.subs = []
  }

  // 消息订阅
  addSub(...subs) {
    subs.forEach(sub => {
      this.subs.push(sub)
    })
  }

  // 消息发布
  notify(...payload) {
    this.subs.forEach(sub => {
      sub.update(payload)
    })
  }

}

// 创建发布者
const p = new Publisher();

// 创建订阅者
const s1 = {
  name: 's1',
  update(payload) {
    console.log(`I am ${this.name}, I like ${payload}`);
  }
}

const s2 = {
  name: 's2',
  update(payload) {
    console.log(`I am ${this.name}, I like ${payload}`);
  }
}

const s3 = {
  name: 's3',
  update(payload) {
    console.log(`I am ${this.name}, I like ${payload}`);
  }
}

// 订阅者订阅消息
p.addSub(s1,s2,s3)

// 发布者发布消息
p.notify('eating','reading','...')

第三版、区分类型

// 发布者类
class Publisher {
  constructor() {
    this._subsMap = {}
  }

  // 订阅消息
  addSub(...subs) {
    subs.forEach(sub => {
      if (this._subsMap[sub['type']]) {
        this._subsMap[sub['type']].push(sub)
      } else {
        this._subsMap[sub['type']] = [sub]
      }
    })
  }

  // 发布消息
  notify(type,...payload) {
    this._subsMap[type].forEach( sub => {
      sub.update(payload)
    })
  }

}

// 创建发布者
const p = new Publisher();

// 创建订阅者
const s1 = {
  name: '小米',
  type: 'eating',
  update(payload) {
    console.log(`${this.name} get a message: ${payload}`);
  }
}

const s2 = {
  name: '腾讯',
  type: 'eating',
  update(payload) {
    console.log(`${this.name} get a message: ${payload}`);
  }
}

const s3 = {
  name: '阿里',
  type: 'reading',
  update(payload) {
    console.log(`${this.name} get a message: ${payload}`);
  }
}

// 订阅者订阅发布者
p.addSub(s1, s2, s3)

// 发布者发布特定类型消息
p.notify('reading','article about reading is update,read it by now~');

p.notify('eating','you are hungry,eating something now~');


// 输出结果

阿里 get a message: article about reading is update,read it by now~
小米 get a message: you are hungry,eating something now~
腾讯 get a message: you are hungry,eating something now~

第四版、一些小的优化(订阅者成类,退订功能)

// 发布者类
class Publisher {
  constructor() {
    this._subsMap = {}
  }

  // 订阅
  subscribe(...subs) {
    subs.forEach(sub => {
      if (this._subsMap[sub['type']]) {
        this._subsMap[sub['type']].push(sub)
      } else {
        this._subsMap[sub['type']] = [sub]
      }
    })
  }

  // 退订
  unSubscribe(...subs) {
    subs.forEach(sub => {
      // 该订阅者未订阅发布者
      if (!this._subsMap[sub['type']].includes) return;

      this._subsMap[sub['type']].forEach((minSub, index) => {
        if (sub['name'] === minSub['name']) {
          this._subsMap[sub['type']].splice(index, 1)
          return;
        }
      })

    })
  }

  // 发布
  notify(type, ...payload) {
    this._subsMap[type].forEach(sub => {
      sub.update(payload)
    })
  }

}

// 订阅者类
class Subscribe {
  constructor(name, type) {
    this.name = name
    this.type = type
  }

  update(payload) {
    console.log(`${this.name} get a message: ${payload}`);
  }
}

// 创建发布者
const p = new Publisher();

// 创建订阅者
const s1 = new Subscribe('小米', 'eating')
const s2 = new Subscribe('腾讯', 'eating')
const s3 = new Subscribe('阿里', 'reading')
const s4 = new Subscribe('头条', 'sleeping')

p.subscribe(s1, s2, s3, s4)

p.notify('reading', 'article about eating is update,read it by now~');

p.notify('eating', 'you are hungry,eating something now~');

p.notify('sleeping', 'sleeping now~');

p.unSubscribe(s2, s4)