观察者模式and发布订阅模式

137 阅读2分钟

什么是观察者模式

我们往往会出现这种需求:当一个对象的行为发生改变时,他的改变会影响到其他对象,使得那些对象相应的做出改变。

那么这个改变的对象我们称之为观察目标,而那些被影响到的对象我们称之为观察者

举个最常见的栗子

当我们需要给某个DOM监听鼠标的点击事件,但我们并不知道用户什么时候点击,需要提前添加相应的事件与点击事件绑定。这个时候点击事件便是观察目标,我们绑定的自定义事件便是观察者。

const box = document.querySelector('.box');
box.addEventListener('click', ()=>{
  console.log('box clicked one');
})
box.addEventListener('click', ()=>{
  console.log('box clicked two');
})

如上简单的代码我们便为box这个DOM加入了两个观察者。

如何自己实现一个观察者模式

这里我们以微信公众号和用户为案例

// 微信公众号
class WeChat {
  constructor(account){
    this.account = account
    this.observer = new Set()
  }
  addObserver(ob){
    this.observer.add(ob)
  }
  removeObserver(ob){
    this.observer.delete(ob)
  }
  pushArticles(content){
    this.observer.forEach(ob=>{
      ob.readArticles(this.account,content)
    })
  }
}
// 微信用户
class Person {
  constructor(user){
    this.user = user
  }
  readArticles(article,content){
    console.log(`${this.user}: ${content}, from ${article}`)
  }
}

// 创建公众号
const account_1 = new WeChat('solo的自我修养')
// 创建微信用户
const user_1 = new Person('nini')
const user_2 = new Person('guapi')
// 加入用户
account_1.addObserver(user_1)
account_1.addObserver(user_2)
// 推送文章
account_1.pushArticles('you are good man')
account_1.removeObserver(user_1)
account_1.pushArticles("don't say something")

总结:

  1. 观察目标要存入所有观察者。
  2. 观察者写入监听时执行的方法。
  3. 在触发观察目标监听事件方法时,遍历所有观察者并执行观察者所需执行的相应方法。

什么是发布订阅模式

大多数文章都提到发布订阅模式是观察者模式的别称。虽然说他们两者确实大相径庭,但在编程思想上还是有其不同之处。

就上面的案例我们用发布订阅模式写会是怎样的呢?

// 公众号作者
class WeChatAuthor {
  constructor(author){
    this.author = author
  }
  writeArticles(admin,article){
    admin.pushArticle(article)
  }
}
// 微信用户
class Person {
  constructor(user){
    this.user = user
  }
  readArticles(article,wechat){
    console.log(`${this.user}用户读了来自 ${wechat}公众号的文章: ${article}`)
  }
}
// 公众号
class WeChatAdmins {
  constructor(wechat){
    this.wechat = wechat
    this.persons = new Set()
  }
  addPerson(person){
    this.persons.add(person)
  }
  removePerson(person){
    this.persons.delete(person)
  }
  pushArticle(article){
    this.persons.forEach(person => {
      person.readArticles(article,this.wechat)
    })
  }
}

// 申请成为公众号作者
const author = new WeChatAuthor('我要暑假')
// 建立公众号
const wechat = new WeChatAdmins('前端暑假旅游度假区')
// 微信用户
const person_1 = new Person('尤雨河')
const person_2 = new Person('尤雨江')
// 关注'前端暑假旅游度假区'公众号
wechat.addPerson(person_1)
wechat.addPerson(person_2)
// 作者通过'前端暑假旅游度假区'公众号发布文章
author.writeArticles(wechat,'Vue3顶呱呱!')

// 输出结果: 
// 尤雨河用户读了来自 前端暑假旅游度假区公众号的文章: Vue3顶呱呱!
// 尤雨江用户读了来自 前端暑假旅游度假区公众号的文章: Vue3顶呱呱!

观察者模式 vs 发布订阅模式

前面我们用两种模式书写了同一个功能案例可以发现两个的不同点。我这里用人话来描述,大家可以细品下区别:

  • 观察者模式:作者在公众号写文章 -> 公众号推送给所有关注的读者
  • 发布订阅模式:作者写好文章 -> 把文章复制粘贴到相应的公众号上 -> 公众号推送给所有关注的读者

区别总结:发布订阅模式是将观察目标观察者进行解耦,创建调度中心的功能中间层。观察者不再与观察目标有直接关联,观察者只需观察调度中心,而观察目标的改变也只需通知调度中心