[Javascript设计模式专栏]实现订阅发布者模式

84 阅读2分钟

发布订阅模式又叫观察者模式,它定义了对象间一对多的依赖关系,一个对象的状态发生改变时,所有依赖他的对象都会得到通知。JS里可以用事件模型来替代发布订阅模式。 (引用自JS设计模式与开发实践)

本文会由浅入深的实现一个订阅发布者模式

一个最简单的订阅发布者模式

一个发布者对象(observer),包括了一个缓存数组(cacheList), 一个订阅方法(listen), 和一个发布方法(trigger),

    var observer =  {};
    observer.cacheList = [];
    observer.listen = function(fn) {
        observer.cacheList.push(fn)
    }
    observer.trigger = function() {
        for(var i = 0; i < observer.cacheList.length; i++) {
            observer.cacheList[i].apply(this, arguments)
        }
    }
    observer.listen(function oneListen(arg) {
        console.log(`第一个订阅者收到:${arg}`)
    })
       observer.listen(function twoLis(arg) {
        console.log(`第二个订阅者收到:${arg}`)
    })
    observer.trigger('推送消息')

我们可以在控制台看到打印 image.png

完整实现

上面实现的是一个只支持对订阅者群发的实现, 完善他的功能

  1. 为每个订阅者添加一个标识(name),可以根据标识筛选出对应的订阅者
  2. 添加一个退订方法(remote)
    var observer: any = {};
    observer.cacheList = {};
    observer.listen = function (key: string, fn: any) {
      if (!observer.cacheList[key]) {
        observer.cacheList[key] = [];
      }
      observer.cacheList[key].push(fn);
    };

    observer.trigger = function (name: string, data: any) {
      if (observer.cacheList[name]) {
        observer.cacheList[name].forEach((e: any) => e(data));
      }
    };

    observer.remote = function (name: string, Fn: any) {
      if (!observer.cacheList[name]) return;
      const index = observer.cacheList[name].indexOf(Fn);
      if (!~index) return;
      observer.cacheList[name].splice(index, 1);
    };

    function oneListen(arg: any) {
      console.log(`第一个订阅者收到:${arg}`);
    }

    observer.listen("oneListener", oneListen);
    function twoLis(arg: any) {
      console.log(`第二个订阅者收到:${arg}`);
    }


    
    // 测试数据
    observer.listen("twoLiser", twoLis);
    observer.trigger("oneListener", "推送消息");
    observer.trigger("twoLiser", "推送消息");
    observer.remote("oneListener", twoLis);
    observer.trigger("oneListener", "推送消息");
    observer.remote("oneListener", oneListen);
    observer.trigger("oneListener", "推送消息");

Class实现

class Observer {
  cacheList: {};
  constructor() {
    this.cacheList = {};
  }
  listen(name, fn) {
    if (typeof name !== "string") {
      throw new Error(" name must be a string");
    }
    if (typeof fn !== "function") {
      throw new Error("fn must be a function");
    }
    if (!this.cacheList[name]) {
      this.cacheList[name] = [];
    }
    this.cacheList[name].push(fn);
  }
  remote(name, fn) {
    if (typeof name !== "string") {
      throw new Error(" name must be a string");
    }
    if (typeof fn !== "function") {
      throw new Error("fn must be a function");
    }
    if (!this.cacheList[name]) return;
    const index = this.cacheList[name].indexOf(Fn);
    if (!~index) return;
    this.cacheList[name].splice(index, 1);
  }
  trigger(name, data) {
    if (typeof name !== "string") {
      throw new Error("name name must be a string");
    }
    if (!this.cacheList[name]) return;
    this.cacheList[name].forEach((callback) => callback(data));
  }
}