一、定义

  在事件驱动的环境中,比如浏览器这种持续寻求用户关注的环境中,观察者模式(又名发布者-订阅者(publisher-subscripber)模式)是一种管理人与其任务之间的关系(确切地讲,是对象及其行为和状态之间的关系)的得力工具.用JavaScript的话来说,这种模式的实质就是你可以对程序中某个对象的状态进行观察,并且在其发生改变时能够得到通知。

二、例子

  我们需要一个发布者的构造函数,它为该实例定义了一个类型为数组的属性,用来保存订阅者的引用。

function Publisher() {
this.subscribers = [];
}

  接下来,构建订阅方法。所有Publisher实例都应该能够投送数据。只要把deliver方法添加到Publisher的prototype中,它就能够被所有Publisher对象共享。

// 订阅者订阅能力
Function.prototype.subscribe = function(publisher) {
var that = this,
alreadyExists = false,
i,
len = publisher.length; for(i = 0; i < len; i++) {
if (el === this) {
alreadyExists = true;
}
} if (!alreadyExists) {
publisher.subscribers.push(this);
} return this;
}; // 订阅者具有退订能力
Function.prototype.unSubscribe = function(publisher) {
var that = this,
array = [],
len = publisher.length; for(i = 0; i < len; i++) {
if (el !== this) {
array.push(this);
}
} publisher.subscribers = array; return this;
};

  应用之——

// 订阅者订阅能力
Function.prototype.subscribe = function(publisher) {
var that = this,
alreadyExists = false,
i,
len = publisher.length; for(i = 0; i < len; i++) {
if (el === this) {
alreadyExists = true;
}
} if (!alreadyExists) {
publisher.subscribers.push(this);
} return this;
}; // 订阅者具有退订能力
Function.prototype.unSubscribe = function(publisher) {
var that = this,
array = [],
len = publisher.length; for(i = 0; i < len; i++) {
if (el !== this) {
array.push(this);
}
} publisher.subscribers = array; return this;
};

三、现实世界中的观察者

  在现实世界中,观察者模式对于那种由许多JavaScript程序员合作开发的大型应用程序特别有用。它可以提高API的灵活性,使并行开发的多个市县能够彼此独立的进行修改。作为开发人员,你可以对自己的应用程序中什么是“令人感兴趣的时刻”做出决定。你所能监听的不再只是click、load、blur和mouseover等浏览器事件。在富用户界面应用程序中,drag(拖动)、drop(拖放)、moved(移动)、complete(完成)和tabSwitch(标签切换)都可能是令人感兴趣的事件。它们都是在普通浏览器事件的基础上抽象出来的可观察事件,可由发布者对象向其监听者广播。

  在DOM脚本编程环境中的高级时间模式中,事件监听器说到底就是一种内置的观察者。事件处理器(handler)与事件监听器(listener)并不是一回事。前者说穿了就是一种把事件传递给与其关联的函数的手段。而且在这种模型中一种事件只能指定一个回调方法。而在监听器模式中,一个事件可以与几个监听器关联。每个监听器都能独立于其他监听器而改变。

// 使用事件监听器,可以让多个函数响应同一个事件
var element = $('#example');
var fn1 = function(e) {
// handle clikc
};
var fn2 = function(e) {
// do other stuff with click
};
// 由于使用的是事件监听器,所以click事件发生时fn1和fn2都会被调用
addEvent(element, 'click', fn1);
addEvent(element, 'click', fn2);
// 但用事件处理器就办不到
var element = $('#example');
var fn1 = function(e) {
// handle clikc
};
var fn2 = function(e) {
// do other stuff with click
};
element.onclick = fn1;
// 第二个onclick赋值的结果是fn1被fn2取代,因此click事件发生时只会调用fn2。
element.onclick = fn2;

  监听器和观察者之间的共同之处显而易见。实际上它们互为同义词。它们都订阅特定的事件,然后等待事件的发生。事件发生时,订阅方的回调函数会得到通知。传给它们的参数是一个事件对象,其中包含着事件发生时间、事件类型和事件发源地等有用的信息。

四、优势

  观察者模式可以削减为事件注册监听器的次数,让可观察对象借助一个事件监听器替你处理各种行为并将信息委托给它的所有订阅者,从而降低内存消耗和提高互动性能,提高程序的可维护性。

五、劣势

  使用这种观察者接口的一个不利之处在于创建可观察对象所带来的加载时间开销。这可以通过惰性加载技术加以化解。

六、小结

  一个事件可以被5个订阅者订阅,而一个订阅者也可以订阅5个不同的事件。对于浏览器这类互动环境来说这非常理想。现在的Web应用程序越来越大,在此背景下,作为一种提高代码的可维护性和简洁性的有力手段,可观察对象的作用更显突出。

【读书笔记】读《JavaScript设计模式》之观察者模式的更多相关文章

  1. 再起航,我的学习笔记之JavaScript设计模式18(观察者模式)

    观察者模式 观察者模式(Observer): 又被称为发布-订阅者模式或消息机制,定义了一种依赖关系,解决了主体对象与观察者之间功能的耦合. 创建一个观察者对象 首先我们创建一个闭包对象,让其在页面加 ...

  2. 读书笔记之 - javascript 设计模式 - 观察者模式

    在事件驱动的环境中,比如浏览器这种持续寻求用户关注的环境中,观察者模式是一种管理人与其任务(确切的讲,是对象及其行为和状态之间的关系)之间的关系的得力工具.用javascript的话来讲,这种模式的实 ...

  3. 读书笔记之 - javascript 设计模式 - 接口、封装和链式调用

    javascript 采用设计模式主要有下面的三方面原因: 可维护性:设计模式有助于降低模块之间的耦合程度.这使代码进行重构和换用不同的模块变得容易,也使程序员在大型项目中合作变得容易. 沟通:设计模 ...

  4. 读书笔记之 - javascript 设计模式 - 命令模式

    本章研究的是一种封装方法调用的方式.命令模式与普通函数有所不同.它可以用来对方法调用进行参数化处理和传送,经过这样处理过的方法调用可以在任何需要的时候执行. 它也可以用来消除调用操作的对象和实现操作的 ...

  5. 读书笔记之 - javascript 设计模式 - 代理模式

    代理(proxy)是一个对象,它可以用来控制对另一对象的访问.它与另外那个对象实现了同样的接口,并且会把任何方法调用传递给那个对象.另外那个对象通常称为本体.代理可以代替本体被实例化,并使其可被远程访 ...

  6. 读书笔记之 - javascript 设计模式 - 享元模式

    本章探讨另一种优化模式-享元模式,它最适合于解决因创建大量类似对象而累及性能的问题.这种模式在javascript中尤其有用,因为复杂的javascript代码很快就会用光浏览器的所有可用内存,通过把 ...

  7. 读书笔记之 - javascript 设计模式 - 门面模式

    门面模式有俩个作用: 简化类的接口 消除类与使用它的客户代码之间的耦合 在javascript中,门面模式常常是开发人员最亲密的朋友.它是几乎所有javascript库的核心原则,门面模式可以使库提供 ...

  8. 读书笔记之 - javascript 设计模式 - 单体模式

    单体是一个用来划分命名空间,并将一批相关方法和属性组织在一起的对象,如果它可以被实例化,那么它只能被实例化一次. 单体模式,就是将代码组织为一个逻辑单元,这个逻辑单元中的代码可以通过单一的变量进行访问 ...

  9. 读书笔记之 - javascript 设计模式 - 组合模式

    组合模式是一种专为创建Web上的动态用户界面而量身定制的模式,使用这种模式,可以用一条命令在对各对象上激发复杂的或递归的行为. 在组合对象的层次体系中有俩种类型对象:叶对象和组合对象.这是一个递归定义 ...

  10. 读书笔记之 - javascript 设计模式 - 工厂模式

    一个类或者对象中,往往会包含别的对象.在创建这种对象的时候,你可能习惯于使用常规方式,即用 new 关键字和类构造函数. 这会导致相关的俩个类之间产生依赖. 工厂模式,就是消除这俩个类之间的依赖性的一 ...

随机推荐

  1. 在纯HTML的静态网页中添加一段统计网页访问量的JAVA Script代码?

    如何在网站上进行流量统计呢,可以找第三方服务网站去注册,但也可以在网站上直接添加代码,只需将以下代码copy到你的网页中,复制到</body>之前就可以啦!是不是很简单啊! <scr ...

  2. PL/0编译器(java version)–Pcode.java

    1: package compiler; 2:   3: /** 4: * //虚拟机指令 5: * 6: * @author jiangnan 7: * 8: */ 9: public class ...

  3. SQL localdb 连接字符串

    http://blog.csdn.net/greystar/article/details/47699797 原来SQL 2012 下连接LOCALDB,字符串为: Data Source=(Loca ...

  4. springmvc常用注解标签详解

    1.@Controller 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ...

  5. Spring学习6-Spring整合Struts2

    一.Spring为什么要整合Struts2     Struts2与Spring进行整合的根本目的就是要让 Spring为Struts2的Action注入所需的资源对象,它们整合的原理则是只要导入了s ...

  6. App接口中xml方式封装通信接口

  7. hdu 2085 核反应堆

    看完题,想到用结构体存储高质点和低质点,然后打表存储<33的质点数量. #include<stdio.h> struct hilo { long long hi,lo; }; int ...

  8. 离线渲染中的不规则光源(Meshlight)

    之前一直在考虑这样一个问题,在实际生活中的光源都是有体积的,但是图形学中,很多时候我们用简单的点光源,面光源,或者方向光来模拟实际生活中这些光源,势必会产生一些误差,同时导致很多效果不好做.那么在离线 ...

  9. Socket网络编程(1)

    TCP/IP 简单介绍 应用层 (Application):应用层是个很广泛的概念,有一些基本相同的系统级 TCP/IP 应用以及应用协议,也有许多的企业商业应用和互联网应用. 传输层 (Transp ...

  10. Forth scrum meeting - 2015/10/29

    今天下午,我们终于要到了MOOC服务器端开发人员的联系方式,于是我们小组派了三名同学去实验室与他们进行了交流,并咨询了他们一些关于API接口的问题.他们也对我们这个客户端的开发提出了一些建议. 开发团 ...