资讯专栏INFORMATION COLUMN

10分钟弄懂一种简单的js设计模式(观察者/发布订阅)

xiguadada / 1959人阅读

摘要:发布者注册发布订阅者自动打印消息消息观察者模式与发布订阅模式类似。在此种模式中,一个目标物件在它本身的状态改变时主动发出通知,观察者收到通知从而使他们的状态自动发生变化。

做为非科班出身的前端er,每次听到设计模式都感觉很高大上,总感觉这些东西是造火箭原子弹用的,距离我们这些造螺丝钉很遥远。但是最近在做一个聊天消息的业务时,发现貌似用上发布订阅模式业务就很清晰了。创建一个消息类当作发布者,展示消息的函数是订阅者,发布者提供了注册、发布方法,订阅者注册后,每次调用发布方法修改数据时,订阅者函数自动更新数据。

class MsgList{//发布者
    constructor (){
        this.list = [];
        this.fn = []
    }
    listen(fn){//注册
      this.fn.push(fn)
    }
    add(text){//发布
        this.list.push(text)
        this.fn.map((item)=>{
            item(this.list)
        })
    }
}
function show(msg){//订阅者
    console.log(msg) //自动打印
}
var msg1 = new MsgList();
msg1.listen(show)
msg1.add("消息1")
msg1.add("消息2")

观察者模式与发布订阅模式类似。在此种模式中,一个目标物件在它本身的状态改变时主动发出通知,观察者收到通知从而使他们的状态自动发生变化。核心就是我(观察者)正在看着你(被观察者),看着你目不转睛...你只要改变我就自动改变。概念是不是很清晰了。但是观察者模式又跟发布订阅有些许不太一样的地方。

一、观察者模式

目标观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察者把自己注册到具体目标里,在具体目标发生变化时候,调度观察者的更新方法。

下面通过js来实现下观察者模式。首先是目标的构造函数,他有个数组,用于添加观察者。还有个广播方法,遍历观察者数组后调用他们的update方法:

class Subject{//目标类===被观察者
    constructor(){
        this.subjectList = [];//目标列表
    }
    add(fn){//注册
        this.subjectList.push(fn)
    }
    notify(context){//发通知    
        var subjectCount = this.subjectList.length
        for(var i=0; i < subjectCount; i++){
            this.subjectList[i].update(context)
        }
    }
    //取消注册
    remove(fn){
        this.subjectList.splice(this.subjectList.indexOf(fn),1)
    }
}

class Observer{//观察者类==观察者
    update(data){
        console.log("updata +" + data)
    }
}

var Subject1 = new Subject()//具体目标1
var Subject2 = new Subject()//具体目标2

var Observer1 = new Observer()//具体观察者1
var Observer2 = new Observer()//具体观察者2

Subject1.add(Observer1);//注册 //updata +test1
Subject1.add(Observer2);//注册 //updata +test1
Subject2.add(Observer1);//注册 //updata +test2

Subject1.notify("test1")//发布事件
Subject2.notify("test2")//发布事件

从上面代码可以看出来,先创建具体目标具体观察者,然后通过add方法把具体观察者 Observer1、Observer2注册到具体目标中,目标和观察者是直接联系起来的,所以具体观察者需要提供update方法。在Subject1中发通知时,Observer1、Observer2都会接收通知从而更改状态。

二、 发布/订阅模式

观察者模式存在一个问题,目标无法选择自己想要的消息发布,观察者会接收所有消息。在此基础上,出现了
发布/订阅模式,在目标和观察者之间增加一个调度中心。订阅者(观察者)把自己想订阅的事件注册到调度中心,当该事件触发时候,发布者(目标)发布该事件到调度中心,由调度中心统一调度订阅者注册到调度中心的处理代码。

class Public{//事件通道
    constructor(){
        this.handlers = {};
    }
    on(eventType, handler) { // 订阅事件
        var self = this;
        if (!(eventType in self.handlers)) {
            self.handlers[eventType] = [];
        }
        self.handlers[eventType].push(handler);
        return self ;
    }
    emit(eventType) {    // 发布事件
        var self = this;
        var handlerArgs = Array.prototype.slice.call(arguments, 1);
        var length = self.handlers[eventType].length
        for (var i = 0; i < length; i++) {
            self.handlers[eventType][i].apply(self, handlerArgs);
        }
        return self;
    }
    off(eventType, handler) {    // 删除订阅事件
        var currentEvent = this.handlers[eventType];
        var len = 0;
        if (currentEvent) {
            len = currentEvent.length;
            for (var i = len - 1; i >= 0; i--) {
                if (currentEvent[i] === handler) {
                    currentEvent.splice(i, 1);
                }
            }
        }
        return self ;
    }
}

//订阅者
function Observer1(data) {
    console.log("订阅者1订阅了:" + data)
}
function Observer2(data) {
    console.log("订阅者2订阅了:" + data)
}

var publisher = new Public();

//订阅事件
publisher.on("a", Observer1);
publisher.on("b", Observer1);
publisher.on("a", Observer2);

//发布事件
publisher.emit("a", "第一次发布的a事件");
publisher.emit("b", "第一次发布的b事件");
publisher.emit("a", "第二次发布的a事件"); 
//订阅者1订阅了:第一次发布a事件
//订阅者2订阅了:第一次发布a事件
//订阅者1订阅了:第一次发布b事件
//订阅者1订阅了:第二次发布a事件
//订阅者2订阅了:第二次发布a事件

可以看出来,订阅/发布模式下:订阅和发布是不直接调度的,而是通过调度中心来完成的,订阅者和发布者是互相不知道对方的,完全不存在耦合。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105790.html

相关文章

  • js设计模式笔记 - 察者模式

    摘要:姓名小强正式上班时间前端大大强订阅了这个消息姓名大大强正式上班时间发布者发布消息前端小强姓名小强正式上班时间大大强姓名大大强正式上班时间通过添加了一个,我们实现了对职位的判断。 观察者模式,定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。 事实上,只要你曾经在DOM节点上绑定过事件函数,那么你就曾经使用过观察者模式了! document.b...

    txgcwm 评论0 收藏0
  • 撸一个JS事件管理模块

    摘要:列举一个生活中的例子来帮助大家理解这一种模式。例子中的小明就是订阅者订阅的是饭凉了,而妈妈则是发布者将信号饭凉了发布出去。这样就不用把小明和妈妈强耦合在一起,当小明的弟弟妹妹都想在饭凉了在吃饭,只需告诉妈妈一声。 关于事件 在我们使用javascript开发时,我们会经常用到很多事件,如点击、键盘、鼠标等等,这些物理性的事件。而我们今天所说的我称之为事件的,是另一种形式的事件,订阅--...

    harryhappy 评论0 收藏0
  • Node.js 异步异闻录

    摘要:的异步完成整个异步环节的有事件循环观察者请求对象以及线程池。执行回调组装好请求对象送入线程池等待执行,实际上是完成了异步的第一部分,回调通知是第二部分。异步编程是首个将异步大规模带到应用层面的平台。 showImg(https://segmentfault.com/img/remote/1460000011303472); 本文首发在个人博客:http://muyunyun.cn/po...

    zzbo 评论0 收藏0
  • [译] 你应了解4种JS设计模式

    摘要:尽管特定环境下有各种各样的设计模式,开发者还是倾向于使用一些习惯性的模式。原型设计模式依赖于原型继承原型模式主要用于为高性能环境创建对象。对于一个新创建的对象,它将保持构造器初始化的状态。这样做主要是为了避免订阅者和发布者之间的依赖。 2016-10-07 每个JS开发者都力求写出可维护、复用性和可读性高的代码。随着应用不断扩大,代码组织的合理性也越来越重要。设计模式为特定环境下的常见...

    awokezhou 评论0 收藏0
  • js 察者

    摘要:观察者模式机动建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。 观察者模式模式简介 观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。 观察者模式机动...

    missonce 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<