设计模式学习日记(2):观察者模式 和 发布订阅模式

68 阅读4分钟

观察者模式

  • 例子:监控
    => 我们坐在教室就是 被观察者
    => 监控后面的老师,就是观察者
    => 当被观察者触发了一些条件,观察者就会触发技能

  • 观察者模式:监控一个对象的状态,一旦状态发生变化,马上触发技能
    => 需要两个构造函数来实现

  1. 创建被观察者
    • 属性,自己的状态
    • 队列,记录都有谁观察着自己,数组[]
    • 方法:设置自己的状态,当我们需要改变的时候,要触发这个方法改变状态
    • 方法:添加观察者
    • 方法:删除观察者
  2. 创建观察者
    • 需要一个身份证明
    • 需要一个技能
            // 观察者模式
            // 定义一个观察者
            class Observer {
                constructor (name,fn=()=>{}){
                  this.name = name;
                  this.fn = fn;
                }
            }
            
            // 创建两个观察者
            const observer1 = new Observer('班主任',(state)=>{
                console.log(`因为:${state}把你爸找来`);
            });
            const observer2 = new Observer('校长',(state)=>{
                console.log(`因为:${state}骂你的班主任`);
            });

            console.log(observer1,observer2);

            // 定义一个被观察者
            class Subject {
                constructor (state){
                    // 记录自己的状态
                    this.state = state;
                    // 用来保存观察着我的人
                    this.observers = [];
                }
                // 设置状态
                setState (state){
                    this.state = state;
                    // 就需要把 我的所有观察着都通知一下
                    this.notify()
                }
                // 添加观察者
                addObserver (observer){
                  const res = this.observers.some(item=>item.name === observer.name);
                  if(res) return
                  this.observers.push(observer);
                }
                // 删除观察者
                removeObserver (observer){
                    this.observers = this.observers.filter(item=>item.name!==observer.name);
                }
                // 通知观察者
                notify (){
                    //告诉他们我的状态变了  
                    this.observers.forEach(item=>item.fn(this.state));
                }
            }

        const xiaoming = new Subject('学习');
        // 给小明添加一个观察者
        xiaoming.addObserver(observer1);
        xiaoming.addObserver(observer2);
        console.log('xiaoming: ', xiaoming);
        xiaoming.setState('学习不好');

发布订阅模式

  • 有一个对象,有人一直看着他
  • 当这个对象发生变化的时候,第三方通知这个看着的人,触发技能
    • 例子:买书
    1. 普通程序员买书
      • 去书店,问,没有,回家
      • 过一会儿再去,问,没有,回家
      • 过一会儿,问,没有,回家
    2. 发布订阅的程序员
      • 去书店,问,没有,留下一个联系方式给店员
      • 一旦有了书,就会接到电话
      • 触发技能去买书
  • 只需要创建一个构造函数
    • 创造一个第三方店员的身份
    • 我们的任务就是模拟一个 addEvntListener()
  • 分析构造函数
    • 属性:消息队列 { click:[fn1,fn2], abc:[fb1,fn2,fn3] }
    • 方法:向消息队列里面添加内容
    • 方法:删除消息队列里面的的内容
    • 方法:触发消息队列里面的内容
 // 发布订阅模式
  // 创建一个三方观察者构造函数
  class Observer {
      constructor (){
        this.message = {}
      }
      // 1. 向消息队列里面添加内容
      on(type,fn){
        // type 我拜托你看着的行为
        // fn 我拜托你在行为发生的时候,告诉你干什么
        
        // 判断消息队列里面是否有这个消息
        if(!this.message[type]){
          this.message[type] = [];
        }
        this.message[type].push(fn);
      }
      // 2. 删除消息队列里面的内容
      off(type,fn){
        // 判断消息队列里面是否有这个消息
        if(!this.message[type]) return;
        // 判断消息队列里面是否有这个函数
        if(!fn){
          this.message[type] = [];
        }else{
          this.message[type] = this.message[type].filter(item=>item!==fn);
        }
      }
      // 3. 触发消息队列里面的内容
      trigger(type){
        // 判断消息队列里面是否有这个消息
        if(!this.message[type]) return;
        // 触发消息队列里面的内容
        this.message[type].forEach(item=>item());
      }
  }

  // 使用构造函数创建一个实例
  const person1 = new Observer();
  // 当你想拜托这个person1 帮你观察一些内容的时候
  // 告诉你一个行为,当行为出现的时候,告诉你干什么
  person1.on('abc',handlerA)

  // 告诉person1,这个事情不用你管了
  // 1. 我只告诉你这个事情不用你管
  // person1.off('abc'); 把消息队列 里面属于a的数组清空掉
  // person1.off('abc',handlerA)

  person1.trigger('abc',9)

  console.log('person1: ', person1);

  function handlerA(){
    console.log('handlerA');
  }

总结

观察者模式发布订阅者模式两个有类似之处也有不同之处,在圈内有说是同一种的也有认为不是一种的,但这都是不是我们要学习的重点,我们学习的重点时了解他们模式的内容,去理解这种实现逻辑的方式并用于项目中。

vue中有用过this.Bus.emit('xxx'),uni中用过 uni.$on('a',(xx)=>{})、uni.$emit('a',xx),这就是利用发布订阅模式实现的,可以理解uni就在内部创造第三方观察者构造函数,用于注册和监听。发布订阅者模式和观察者模式的主要区别如下图:

image.png

观察者模式:是由具体目标调度,比如当事件触发,Dep就会去调用观察者的方法,所以观察者模式得到订阅者与发布者之前的存在是依赖的

发布/订阅模式由统一调度中心调用,因此发布者和订阅者不需要知道对方的存在