观察者模式,发布-订阅者模式

JS设计模式

设计模式:是一套被反复使用,多数人知晓的,经过分类的,代码设计经验的总结。换言之,就是用 “套路” 做事情。

  • 观察者模式
  • 发布 - 订阅者模式

观察者模式

我们假设你正在找一份软件工程师的工作,对“香蕉公司”很感兴趣。所以你联系了他们的HR,给了他你的联系电话。他保证如果有任何职位空缺都会通知你。这里还有几个候选人也你一样很感兴趣。所以职位空缺大家都会知道,如果你回应了他们的通知,他们就会联系你面试。

所以,以上和“观察者模式”有什么关系呢?这里的“香蕉公司”就是Subject,用来维护Observers(和你一样的候选人),为某些event(比如职位空缺)来通知(notify)观察者。

  • 被观察者实例化 观察者实例化
  • 被观察者添加观察者
  • 被观察者改变状态,触发通知所有观察者的函数

简单实现就是被观察者里面存储了观察者的对象列表,当被观察者发生某种行为时,会回调观察者的方法。

// 被观察者对象
class Student {
  constructor(name) {
    this.s_name = name
    this.state = '学习'
    this.observer = [] // 观察者数组
  }

  // 获取状态的方法
  getter() {
    return this.state
  }

  // 改变状态的同时通过方法通知观察者
  setState(state) {
    this.state = state
    this.notice()
  }

  // 添加观察者
  attash(observer) {
    this.observer.push(observer)
  }

  // 通知观察者
  notice(observer) {
    this.observer.forEach(v => {
      v.sayHello(this.s_name, this.state)
    });
  }
}

// 观察者对象
class Teacher {
  constructor(name) {
    this.t_name = name
  }

  // 被观察者通知观察者执行的方法
  sayHello(name, state) {
    console.log('我是' + this.t_name + ',学生' + name + '现在的状态为:' + state);
  }
}

// 实例化被观察者
stu = new Student('小明')

// 实例化观察者
t1 = new Teacher('王老师')
t2 = new Teacher('张老师')

// 添加观察者
stu.attash(t1)
stu.attash(t2)

// 被观察者触发了改变状态的方法,就会通知到观察者,观察者执行对应的方法
stu.setState('写作业')

发布 - 订阅者模式

在观察者模式中的Subject就像一个发布者(Publisher),而观察者(Observer)完全可以看作一个订阅者(Subscriber)。subject通知观察者时,就像一个发布者通知他的订阅者。这也就是为什么很多书和文章使用“发布-订阅”概念来解释观察者设计模式。但是这里还有另外一个流行的模式叫做发布-订阅设计模式。它的概念和观察者模式非常类似。最大的区别是:

在发布-订阅模式,消息的发送方,叫做发布者(publishers),消息不会直接发送给特定的接收者(订阅者)。

意思就是发布者和订阅者不知道对方的存在。需要一个第三方组件,叫做信息中介,它将订阅者和发布者串联起来,它过滤和分配所有输入的消息。换句话说,发布-订阅模式用来处理不同系统组件的信息交流,即使这些组件不知道对方的存在。

那么如何过滤消息的呢?事实上这里有几个过程,最流行的方法是:基于主题以及基于内容。

发布 - 订阅模式分为3个状态

  • 订阅
  • 取消订阅
  • 发布
// 发布-订阅模式

// 消息中心
function message1(data) { console.log('这是message1函数', data); }
function message2(data) { console.log('这是message2函数', data); }
function message3(data) { console.log('这是message3函数', data); }
function message4(data) { console.log('这是message4函数', data); }
function message5(data) { console.log('这是message5函数', data); }
function message6(data) { console.log('这是message6函数', data); }

class Observer {
  constructor() {
    this.message = []
  }
  // 订阅
  on(type, fun) {
    if (!this.message[type]) {
      this.message[type] = []
    }
    this.message[type].push(fun)
  }
  // 取消订阅
  off(type, fun) {
    if (!this.message[type]) return
    this.message[type] = this.message[type].filter(v => {
      return v != fun
    })
  }
  // 发布事件
  emit(type, val) {
    const data = {
      type,
      data: val
    }
    if (!this.message[type]) return
    this.message[type].forEach(v => { // 基于type
      v(data)
    });
  }
}

// 实例化发布者
const ob1 = new Observer()

// 发布者添加消息中心
ob1.on('type_a', message1)
ob1.on('type_a', message2)
ob1.on('type_a', message3)
ob1.on('type_a', message4)
ob1.on('type_b', message5)
ob1.on('type_b', message6)

// 实例化两个订阅者
const subscriber1 = {
  name: '小明',
  boo: true,
  arr: [1, 2, 3]
}
const subscriber2 = {
  name: '小红',
  boo: false,
  arr: [4, 5, 6]
}

// 发布者将订阅者的数据分发给消息中心
ob1.emit('type_a', subscriber1)
ob1.emit('type_b', subscriber2)

console.log('-----------------------------');

ob1.off('type_a', message1)
ob1.off('type_b', message6)

ob1.emit('type_a', subscriber1)
ob1.emit('type_b', subscriber2)

总结一下:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值