`
wolferill
  • 浏览: 59243 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

JavaScript设计模式-观察者模式

阅读更多

 

观察者模式(Observer Pattern),也被称为“发布/订阅模型(publisher/subscriber model)”。在这种模式中,有两类对象,分别是“观察者-Observer”和“目标对象-Subject”。目标对象中保存着一份观察者的列表,当目标对象的状态发生改变的时候就主动向观察者发出通知(调用观察者提供的方法),从而建立一种发布/订阅的关系。这一种发布/订阅的关系常用于实现事件、消息的处理系统。

在我们的生活中,也存在着许多观察者模式,最简单的例子就是“微博”。关注和被关注的关系,其实就是一个发布/订阅模型。假如,方舟子“悄悄关注”了天才韩寒,韩寒在微博上每发出一条消息都会反馈到方舟子的消息列表中,方舟子便可端坐家中,阴阴一笑,“嘿嘿,小子你干了什么我都知道……”,然后方舟子就开始行动了。

 

传统的观察者模式

我们先看看传统的观察者模式是怎样的吧(Java版):

//被观察者
public class Subject{
    private Array obArray = new Array();
    //增加一个观察者
    public void addObserver(Observer o){
        this.obArray.add(o);
    }
    //删除一个观察者
    public void removeObserver(Observer o){
        this.obArray.remove(o);
    }
    //通知所有观察者
    public void notifyObservers(){
        for(Observer o: this.obArray){
            o.update();
        }
    }
    public void doSomething(){
        //更新状态,告诉所有观察者
        this.notifyObservers();
    }
}
//观察者
public class Observer{
    public void update(){
        //目标对象更新了,要做点什么了
    }
}
 

使用观察者模式的好处是,当一个对象A需要通知另外一个对象B的时候,无需在A中声明B,在保持相关对象行为一贯性的时候,避免对象之间的紧耦合,这样可以使对象有很好的重用性。

 

DOM中的观察者模式

JavaScript是一个事件驱动型语言,观察者模式可谓随处可见,例如:

document.body.onclick = function(){
    alert('我是一个观察者,你一点击,我就知道了');
}
//或者是
document.body.addEventListener('click',function(){
    alert('我也是一个观察者,你一点击,我就知道了');
});
 我们给body结点添加了一个onclick事件,一点击就会弹出对话框,这里面就存在着一个发布/订阅的模型。其中,body是发布者,即目标对象,当被点击的时候,向观察者反馈这一事件;JavaScript中函数也是一个对象,click这个事件的处理函数就是观察者,当接收到目标对象反馈来的信息时进行一定处理。

这个例子中的发布/订阅关系是由JavaScript语言本身实现的,DOM的每个节点都可以作为Subject,提供了很多事件处理(Event handle)的接口,你只需要给这些接口添加监听函数(也就是Observer),就可以捕获触发的事件进行处理。

 

JavaScript的观察者模式

然而在我们自己写的对象中,要实现这种发布/订阅的关系,就需要自己来实现这个观察者模型,例如:

var ObserverPattern= function(){
    //基于事件的观察者列表
    this.eventObsArray = {};
}
ObserverPattern.prototype = {
    //通知某个事件的所有观察者
    notifyObservers: function(eventName,datas){
        var observers= this.eventObsArray[eventName]||[],i,ob;
        for(i=0;ob=observers[i];i++){
            ob.handler.apply(ob.scope,datas||[]);
        }
    },
    //给某个事件添加观察者
    addObserver: function(eventName,handleFunction,observer){
        var events = this.eventObsArray,
        events[eventName] = events[eventName]||[];
        events[eventName].push({
            //传入的observer参数是handleFunction中的this
            scope: observer || this,
            handler: handleFunction
        });
    },
    //取消某个观察者对某事件的观察
    removeObserver: function(eventName,observer){
        var evts = this.eventObsArray;
        if(!evts[eventName]) return;
        evts[eventName]=evts[eventName].filter(function(ob){
            return ob.scope!=observer;
        });
    }
}
var 韩寒 = new ObserverPattern();
var 方舟子 = {
    doSomeResearch: function(){alert('嘿嘿…我在搞研究…')}
}
//韩寒一写博客,方舟子就开始研究了
韩寒.addObserver('写博客',function(){
    this.doSomeResearch();
},方舟子);
 看过了传统的观察者模式,再看JavaScript版的,或许你会好奇,怎么只有Subject,那个Observer类去哪了?因为在JavaScript中,函数也是一等公民,是对象,无需依赖于其他对象而存在,因此无需专门写一个Observer的构造函数,所有对象都可以做Observer(是不是觉得比传统的灵活多了)。

然而这种形式的发布/订阅模型,还是有些不足的地方,整个关系链条是由目标对象维护的,观察者无法主动去监听目标对象的变化;其次,观察者不知道其他观察者的存在,有时一个观察者的处理有时还会触发其他的事件,无法让其他观察者进行后续处理。

 

既是目标对象也是观察者

方舟子观察韩寒,难道韩寒就不可以看看方舟子了?其实,目标对象也可以是观察者,咱们对上面的ObserverPattern再改进改进:

var ObserverPattern= function(obj){
    for(var i in obj){
        this[i] = obj[i];
    }
    this.eventObsArray = {};
}
ObserverPattern.prototype = {
    //监听某个目标对象
    listen: function(subject, eName, handler){
        subject.addObserver(eName, handler, this)
    },
    //取消监听某个目标对象
    ignore: function(subject, eName){
        subject.removeObserver(eName,this);
    },
    //之前定义的方法,这里就不多说了
    notifyObservers: function(eName,datas){},
    addObserver: function(eName,handler,ob){},
    removeObserver: function(eName,ob){}
}
 
var 韩寒 = new ObserverPattern({
    postReward: function(){alert('研究吧, 奖金2000万…')},
    writeBlog: function(){this.notifyObservers('写博客')}
});
var 方舟子 = new ObserverPattern({
    doSomeResearch: function(){
        alert('嘿嘿…我在搞研究…');
        this.notifyObservers('搞研究')
    }
});
 
//韩寒一发微博,方舟子就开始研究了
方舟子.listen(韩寒,'写博客',方舟子.doSomeResearch);
 
//方舟子一开始研究,韩寒就发赏金了
韩寒.listen(方舟子,'搞研究',韩寒.postReward);
 一个事件可能会产生多方面的影响,而事件消息的发出者不一定能知道所有被影响的对象。将目标对象和观察者整合起来之后,观察者就可以主动监听目标对象,无需目标对象来维护整个关系链条;从开发的角度来说,模块的划分更加明确,无需关注外部模块的实现,只需要监听它们发出的事件即可。

同时,当把目标对象和观察者整合到一起的时候,就形成了一条事件的触发链,一个事件可以触发另一个事件,一个观察者可以将自己观察的结果告诉其他观察者。当然,也要小心事件的循环促发,或者像”蝴蝶效应”那样让一个无关紧要的事件产生过大的影响。

 

更加灵活的事件管理方式

上面的ObserverPattern已经相对完善了,但是使用起来还是有不少限制。例如,需要保证目标对象和观察者先被创建才被调用;一个事件只能被一个目标对象触发,无法一个事件监听多个消息来源。虽然这些也不算什么大问题,但是还有一种更加灵活的方式来管理我们的事件。

//全局的事件监听模块,可用于对象之间的消息传递
var Event = (function(){
    var events = {},
    registerEvent = function(eName, handler, scope){
        events[eName] = events[eName] || [];
        events[eName].push({
            scope: scope || this,
            handler: handler
        });
    },
    removeEvent = function(eName, handler, scope){
        scope = scope || this;
        if(!fns) return;
        events[eName] = events[eName].filter(function(fn){
            return fn.scope!=scope || fn.handler!=handler
        });
    },
    triggerEvent = function(eventName,params){
        var fns = events[eventName],i,fn;
        if(!fns) return;
        for(i=0;fn=fns[i];i++){
            fn.handler.apply(fns.scope,params||[]);
        }
    };
    return {
        listen: registerEvent,
        ignore: removeEvent,
        trigger: triggerEvent
    }
})();
 
Event.listen('韩寒写博客', 方舟子.doSomeResearch, 方舟子);
(function(){
    alert('我是路人甲,我告诉方舟子,韩寒写博客了');
    Event.trigger('韩寒写博客');
})();
 到了这一步,目标对象已经完全的被淡化,是谁发布的信息已经无关紧要了,开发时只需关注观察者对事件的处理方式。方舟子的研究已经不依赖于韩寒的存在,只需要有网友不断的给他提供小道消息,方舟子就可以挖掘出越来越多有趣的东西来了 ~

这种方式的确更为灵活,但越是灵活就越是不好把握,这是一把双刃剑,要小心使用。这种情况下,观察者与目标对象之间的依存关系是很难被跟踪的,很容易像“蝴蝶效应”那样产生意想不到的结果。

 

最后说一下,韩粉方粉别太在意,我不是故意拿你们教主来开刷的,只是碰巧这样很形象嘛 [嘻嘻] ~

 

相关文章

 

0
0
分享到:
评论

相关推荐

    JavaScript设计模式.pdf

    JavaScript设计模式.pdf JavaScript设计模式是指在软件开发中使用JavaScript语言编写的设计模式。这些设计模式旨在提高代码的重用性、可读性、维护性和扩展性。以下是JavaScript设计模式的知识点总结: 1. 单体...

    JAVASCRIPT设计模式[收集].pdf

    常见的JavaScript设计模式包括单例模式、工厂模式、观察者模式、发布-订阅模式等。每种模式都有其适用场景和特点,掌握它们可以让开发者在面对不同的编程问题时,更加高效地应对。 单例模式保证一个类只有一个实例...

    Javascript 设计模式系统讲解与应用

    在深入探讨《JavaScript设计模式系统讲解与应用》的内容之前,我们先来了解一下设计模式的基本概念以及为什么它对于前端开发人员尤为重要。设计模式是一套被反复使用的、经过分类编目的、包含结构化的解决方案,用于...

    javascript 面向对象编程.pdf javascript 设计模式与开发实践.pdf

    在JavaScript中,常见的设计模式包括工厂模式、单例模式、观察者模式、装饰器模式、代理模式等。例如,工厂模式可以用来创建对象,避免直接使用new操作符,提高代码的可扩展性;单例模式确保一个类只有一个实例,常...

    javascript实现观察者模式

    观察者模式(Observer Pattern)是设计模式中的一种行为模式,它允许一个对象,当其状态发生改变时,能够自动通知所有依赖它的对象。在JavaScript中,观察者模式的实现可以帮助我们构建可扩展、松耦合的系统。这篇...

    javascript-978-1-7858-8216-6:掌握 JavaScript 设计模式 - 第二版

    **JavaScript设计模式——第二版** 在编程领域,设计模式是一种被广泛接受的解决方案,它针对特定问题或场景提供了经过时间考验的最佳实践。JavaScript,作为互联网上最常用的语言之一,其设计模式同样至关重要,有...

    JavaScript设计模式之观察者模式(发布者-订阅者模式)

    在JavaScript中,观察者模式也被称作发布-订阅模式(Publish-Subscribe Pattern),是一种行为设计模式,它允许对象之间通过事件来通信。 观察者模式的核心概念包括观察者(Observer)和目标(Subject)。观察者是...

    Javascript 设计模式系统讲解与应用视频资源地址.7z

    JavaScript设计模式是编程实践中的一种重要思想,它提供了一套经过时间考验的最佳实践,用来解决常见的编程问题和提高代码的可维护性、可扩展性和可复用性。在JavaScript这种动态类型的脚本语言中,设计模式尤其重要...

    设计模式-1

    - 观察者模式:定义对象间的一种一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。 - 状态模式:允许对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类...

    设计模式-7种开发语言(C#、JAVA、JavaScript、C++、Python、Go、PHP).pdf

    在标题提及的《设计模式-7种开发语言(C#、JAVA、JavaScript、C++、Python、Go、PHP)》中,作者林晨一点详细介绍了24种经典的设计模式,并提供了这七种主流编程语言的代码示例。以下将对其中一些关键的设计模式进行...

    设计模式之观察者模式1

    【观察者模式】是软件设计模式中的一种行为模式,它实现了对象之间的一对多依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。这种模式在JavaScript中通常通过回调函数来实现,常...

    JavaScript高级与设计模式.zip

    接下来,我们讨论JavaScript设计模式。设计模式是在特定场景下解决问题的通用、可重用的解决方案。在JavaScript中,常见的设计模式有: 1. **单例模式(Singleton)**:确保一个类只有一个实例,并提供一个全局访问...

    学习JavaScript 设计模式

    JavaScript设计模式覆盖了从传统的软件工程设计模式到特定于前端的MV*模式。例如,构造器模式、模块化模式、单例模式、观察者模式等,都是JavaScript中常见的模式,每种模式都旨在解决特定的设计问题。 现代...

    JavaScript 设计模式.zip

    在本压缩包中包含的文件中,"literals-and-constructors"、"function-patterns"、"jquery-plugin-patterns"、"general-patterns" 等文件夹名称暗示了本资源包含了关于各种JavaScript设计模式的详细介绍和示例代码。...

    【JavaScript设计模式】根据曾探所著《JavaScript设计模式与开发实践》整理的学习笔记_pgj.zip

    JavaScript设计模式是软件开发领域中一个非常重要的概念,它为编程人员提供了一套标准的解决方案,以解决在软件设计中遇到的常见问题。曾探所著的《JavaScript设计模式与开发实践》是一本专注于JavaScript语言的模式...

    JavaScript设计模式与开发实践_himppf_js_jspremise_精通javascript_Js设计模式_

    JavaScript设计模式与开发实践是深入理解并提升JavaScript编程能力的关键领域。设计模式是对在软件设计中经常出现的问题的解决方案的描述,它代表了最佳实践,是经验丰富的开发者们经过时间检验后总结出来的解决常见...

    JavaScript中的观察者模式:构建响应式编程的基石

    在软件开发中,观察者模式是一种常见的设计模式,它定义了对象之间的一对多依赖关系,当一个对象状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。在JavaScript中,观察者模式可以通过多种方式实现,包括...

    深入理解JavaScript中的观察者模式:实现与应用

    观察者模式是一种软件设计模式,用于实现对象间的一种一对多的依赖关系。当一个对象改变状态时,所有依赖于它的对象都会收到通知并作出相应的更新。在JavaScript中,观察者模式的应用可以提升程序的可维护性和扩展性...

    java源码设计模式-javascript-design-patterns-source-code:用JavaScript语言合成设计模式的源

    3. 行为型设计模式:这一类模式主要关注对象间通信和职责分配,例如观察者模式(Observer)、模板方法模式(Template Method)、策略模式(Strategy)、命令模式(Command)、迭代器模式(Iterator)、访问者模式...

Global site tag (gtag.js) - Google Analytics