Skip to content

观察者模式

基本概念

观察者模式又叫发布订阅模式,是指发布者和观察者属于一对多的关系,当发布者改变时,会通知观察者做相应处理。

观察者模式有几个关键点:观察者、订阅者、订阅函数、触发器、取消订阅函数、只订阅一次、通知。

使用场景

  • 数据响应式更新。Vue、React 中的数据绑定,当数据发生变化时,使用这些数据的视图组件就会自动更新,从而保证数据的同步
  • 前端页面中注册的各种事件和回调函数
  • 表单校验。表单内各种组件 value 改变时触发的自动校验功能
  • 各种消息通知系统。比如观察对象发生改变时,发送邮件、短信通知等

案例 1:放学(简易版)

老师说放学的时候,学生就会想着去干各自的事情,其中老师就是发布者,等待放学的学生就是观察者。

js
function Teacher() {
  // 订阅者都会存在这里
  this.subscribers = [];

  // 发布事件方法
  this.xiaKeEvent = function () {
    console.log("同学们,下课了!~");
    this.subscribers.forEach((item) => {
      item.say();
    });
  };

  // 订阅方法
  this.subscribe = function (student) {
    this.subscribers.push(student);
  };
}

function Student(name, hobby) {
  this.name = name;
  this.hobby = hobby;
  teacher.subscribe(this);
}
Student.prototype.say = function () {
  console.log(`哈哈哈哈!~${this.hobby}`);
};

let teacher = new Teacher();
// 订阅
let xiaoming = new Student("小明", "打王者");
let xiaohong = new Student("小红", "打篮球");
let xiaowang = new Student("小王", "回家吃饭");

// 老师在这里发布下课事件
teacher.xiaKeEvent();

案例 2:动物餐厅(健全版)

我们再写一个更健全的发布订阅模式,动物餐厅老板在开门前,各种小动物提前订阅老板开饭的通知。

js
let HotelBoss = function () {
  this.subscribers = [];
  // 订阅
  this.subscribe = function (animal) {
    this.subscribers.push(animal);
  };
  // 取消订阅
  this.unsubscribe = function (key, value) {
    this.subscribers = this.subscribers.filter((item) => item[key] != value);
  };
  // 通知
  this.notice = function () {
    this.subscribers.forEach((animal) => {
      animal.trigger();
    });
  };
};

let AnimalsRegister = function (name, hobby) {
  this.name = name;
  this.hobby = hobby;
  // 响应器
  this.trigger = function () {
    console.log(`${name}: ${hobby}`);
  };
  // 取消订阅
  this.unsubscribe = function () {
    hotel.unsubscribe("name", this.name);
  };
  hotel.subscribe(this);
};

// 这里对发布者和订阅者进行声明注册和订阅
let hotel = new HotelBoss();
let cat = new AnimalsRegister("小咪", "喵喵喵,我爱吃鱼");
let dog = new AnimalsRegister("旺财", "旺旺旺,我要吃肉");
let cow = new AnimalsRegister("小花", "哞哞,哥们来点草");

// 餐厅老板发布可以点餐的消息,此时三个动物都正常接到消息了
hotel.notice();

// 此时旺财着急饿得慌,跟老板说不等了出去吃现成的
dog.unsubscribe();

// 老板再发布消息,旺财就接不到了
hotel.notice();