首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript设计模式之观察者模式

JavaScript设计模式之观察者模式

作者头像
用户6167509
发布2019-09-04 10:27:18
3340
发布2019-09-04 10:27:18
举报
文章被收录于专栏:一路向前端一路向前端

观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

主要解决的问题:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

下面通过一个小例子来理解观察者模式:

//观察者
var Observer = function(name){
    this.name = name;
                
    this.updata = function(msg){
        console.log(this.name + msg);
    }
};
            
//被观察者
var Subject = {
    observers: [],
                
    //发布
    publish: function(msg){
        var arr = this.observers;
        for(var i = 0; i < arr.length; i++){
            arr[i].updata(msg);
        }
    },
                
    //添加订阅者
    add: function(name){
        var arr = this.observers;
        if(!arr.includes(name)){
            arr.push(name);
        }
    },
                
    //移除订阅者
    remove: function(name){
        var 
        arr = this.observers,
        index = arr.indexOf(name);
                        
        if(index === -1) return;
        arr.splice(index);
    }
};
            
            
var joe = new Observer("joe");
var john = new Observer("john");
var jofun = new Observer("jofun");
            
Subject.add(joe);
Subject.add(john);
Subject.add(jofun);
            
//被观察者发布消息
Subject.publish("收到订阅消息!");

这个例子是通过模拟传统语言java实现的观察者模式,实现的关键是在被观察者(Subject)内部用一个数组observers存放观察者。在JavaScript中,函数作为一等对象,并且可以作为参数将其传入到其他函数内部执行,所以JavaScript是通过回调函数实现的观察者模式,实现过程更简单、更便捷。

用JavaScript回调实现观察者模式:

//被观察者
var Subject = {
    observers: [],
                
    //发布
    publish: function(){
       var arr = this.observers;
           for(var i = 0; i < arr.length; i++){
               arr[i]();
           }
    },
                
    //添加订阅者
    add: function(name){
        var arr = this.observers;
        if(!arr.includes(name)){
            arr.push(name);
        }
    },
                
    //移除订阅者
    remove: function(name){
        var 
        arr = this.observers,
        index = arr.indexOf(name);
                        
        if(index === -1) return;
        arr.splice(index);
    }
};
            
Subject.add(function(){
    console.log("小明收到订阅消息!")
});
            
//被观察者发布消息
Subject.publish();

上面的代码虽然实现了观察者模式,但是有明显的缺陷,存在匿名函数无法退订的问题。下面修改一下代码,实现退订功能:

//被观察者
var Subject = {
    //用对象存储观察者
    observers: {},
                
    //发布
    publish: function(){
        for(var k in this.observers){
            this.observers[k]();
        }
    },
                
    //添加订阅者
    add: function(name, callback){
         if(name in this.observers) return;
         this.observers[name] = callback;
    },
                
    //移除订阅者
    remove: function(name){
        if(! name in this.observers) return;
        delete this.observers[name];
    }
};
            
Subject.add('foo',function(){
    console.log("小明收到订阅消息!")
});
            
Subject.add('bar',function(){
    console.log("小红收到订阅消息!")
});
            
//退订
Subject.remove('name')
            
//被观察者发布消息
Subject.publish();

通用的观察者模式

为了方便使其他对象具有观察者发布订阅的功能,我们定义一个通用的函数,然后将该函数的功能应用到需要观察者功能的对象上,代码如下:

var Observer = {
    //订阅
    add: function(name, callback){
         if(name in this.observers) return;
         this.observers[name] = callback || null;
    },
                
    //退订
    remove: function(name){
        if(! name in this.observers) return;
        delete this.observers[name];
    },
                
    //发布
    publish: function(){
        var observers = this.observers;
        for(var k in observers){
            if(typeof observers[k] !== "function") continue;
            observers[k].apply(this.publish, arguments);
        }
    },
                
    //使对象 obj具有观察者功能
    create: function(obj){
        var o = obj || {};
        for(var k in this){
            o[k] = this[k];
            o.observers = {};
        }
        return o;
    }
};

接下来测试一下通用的观察者模式代码:

//创建观察者            
var obser = Observer.create();

//订阅
obser.add('foo', function(msg){
    console.log("小明收到" + msg);
});

obser.add('bar', function(msg){
    console.log("小红收到" + msg);
});

//退订
obser.remove('foo');
            
//发布
obser.publish("来自天天时事周报的消息!");    //小红收到来自天天时事周报的消息!

观察者模式优缺点:

优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。

缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-03-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档