定义

观察者模式 在软件设计中是一个对象,维护一个依赖列表,当任何状态发生改变自动通知它们。

image.png

demo

举例

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

代码

发布者

  1. //发布者
  2. class Subject{
  3. constructor(){
  4. this.obseverse = []
  5. }
  6. add(observe){
  7. this.obseverse.push(observe)
  8. }
  9. notify(data){
  10. this.obseverse.forEach( observe=> observe.update(data))
  11. }
  12. }

观察者

  1. // 观察者
  2. class Observer {
  3. update(data) {
  4. console.log(data);
  5. }
  6. }

为发布者添加观察者

  1. let subject = new Subject();
  2. let ob = new Observer();
  3. //目标添加观察者了
  4. subject.add(ob);
  5. //目标发布消息调用观察者的更新方法了
  6. subject.notify(); //update

subject通知观察者就像一个发布者通知他的订阅者。这也就是很多书和文章使用“发布-订阅”概念来解释观察者设计模式


延伸-发布订阅模式

定义

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

意思就是发布者和订阅者不知道对方的存在。需要一个第三方组件,叫做信息中介
image.png

代码

  1. class Event {
  2. constructor () {
  3. // 储存事件的数据结构
  4. // 为查找迅速, 使用对象(字典)
  5. this._cache = {}
  6. }
  7. // 订阅
  8. on(type, callback) {
  9. // 为了按类查找方便和节省空间
  10. // 将同一类型事件放到一个数组中
  11. // 这里的数组是队列, 遵循先进先出,
  12. // 即新绑定的事件先触发
  13. if(this._cache[type]){
  14. // 如果该消息存在
  15. let fns = this._cache[type];
  16. if(!fns.includes(callback)){
  17. fns.push(callback)
  18. }
  19. }else {
  20. this._cache[type] = [callback]
  21. }
  22. return this
  23. }
  24. // 发布
  25. trigger(type, data) {
  26. let fns = this._cache[type];
  27. if(Array.isArray(fns)) {
  28. fns.forEach((fn) => {
  29. fn(data)
  30. })
  31. }
  32. return this
  33. }
  34. // 解绑
  35. off (type, callback) {
  36. let fns = this._cache[type];
  37. if(Array.isArray(fns)) {
  38. if(callback) {
  39. let index = fns.indexOf(callback);
  40. if(index !== -1) {
  41. fns.splice(index, 1)
  42. }
  43. } else {
  44. // 全部清空
  45. fns.length = 0
  46. }
  47. }
  48. return this
  49. }
  50. }
  51. // 创建了一个发布中心
  52. var observer = new Event();
  53. // 某某某订阅了go事件
  54. observer.on('go',function () {
  55. console.log(111);
  56. });
  57. observer.on('go',function (option) {
  58. console.log(222);
  59. console.log(option.url);
  60. });
  61. // go事件执行了并通知了他的订阅对象
  62. observer.trigger('go',{data:"hello",url:'http://wanghai.ml'});

区别

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