# 发布订阅模式

发布订阅的核心: 每次event. emit(发布),就会触发一次event. on(注册)

let fs = require('fs'); 
let school = {}

let event = { // 订阅和发布没有明显的关联,arr是它们的纽带
  arr: [], 
  
  on(fn) {
    this.arr.push(fn); // 将函数依次存储到数组中
  }, 
  emit() {
    this.arr.forEach(fn => fn());  // 将数组中的函数统一执行
  }
}

event.on(function () {
  if (Object. keys(school).length === 2) {
    console.log(school)
  }
})
event.on(function () {
  console.log('读取了一个')
})

fs.readFile('. /name. txt', 'utf8', function (err, data) {
  school.name = data; 
  event.emit(); 
}); 
fs.readFile('. /age. txt', 'utf8', function (err, data) {
  school.age = data; 
  event.emit(); 
}); 

# 观察者模式

观察者模式(基于发布订阅模式) 有观察者,也有被观察者

观察者需要放到被观察者中,被观察者的状态变化需要通知观察者 我变化了 内部也是基于发布订阅模式,收集观察者,状态变化后要主动通知观察者

class Subject { // 被观察者 学生
  constructor(name) {
    this.state = '开心的'
    this.observers = []; // 存储所有的观察者
  }
  // 收集所有的观察者
  attach(o){ // Subject. prototype. attch
    this.observers.push(o)
  }
  // 更新被观察者 状态的方法
  setState(newState) {
    this.state = newState; // 更新状态
    // this 指被观察者 学生
    this.observers.forEach(o => o.update(this)) // 通知观察者 更新它们的状态
  }
}

class Observer{ // 观察者 父母和老师
  constructor(name) {
    this.name = name
  }
  update(student) {
    console.log('当前' + this.name + '被通知了', '当前学生的状态是' + student.state)
  }
}

let student = new Subject('学生'); 

let parent = new Observer('父母'); 
let teacher = new Observer('老师'); 

// 被观察者存储观察者的前提,需要先接纳观察者
student. attach(parent); 
student. attach(teacher); 
student. setState('被欺负了')

# 发布订阅模式的与观察者模式的区别




从图中可以看出,观察者模式中观察者目标直接进行交互,而发布订阅模式中统一由调度中心进行处理,订阅者和发布者互不干扰。这样一方面实现了解耦,还有就是可以实现更细粒度的一些控制。比如发布者发布了很多消息,但是不想所有的订阅者都接收到,就可以在调度中心做一些处理,类似于权限控制之类的。还可以做一些节流操作。