卤煮在大概一年前写过backbone的源码分析,里面讲的是对一些backbone框架的方法的讲解。这几天重新看了几遍backbone的源码,才发现之前对于它的理解不够深入,只关注了它的一些部分的细节和实现技巧。忽略了它的设计思想,而卤煮认为,一套库或者框架最值得借鉴的地方正好是它的设计思想。也巧,最近卤煮在读《设计模式与实践》这本书,所以温故知新,学以致用,打算写一篇博客算作这个系列的补充,以免将来忘记了代码时可以作为参考。

观察者模式

即使不用读源码,也知道backbone使用了观察者模式。因为它本身就是一套mvc框架,而mvc框架核心的就是m(模型)->v(视图)->c(控制器)的交互过程,观察者模式是驱动它们的核心模式之一。我们首先来回顾一下观察者模式的具体定义是如何的:

//定义对象之间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都将得到通知

观察者模式也可以称之为发布-订阅者模式,它需要一些订阅对象,通常它们会自己处理不同的逻辑,简单来说它们就是一些方法。这些方法需要被缓存起来,也就是说需要一个缓存对象缓存他们,等待需要的时候调用。然后我们还需要一个发布者,它负责发布通知,告诉程序,应该去读我们之前缓存起来的订阅对象了。概括起来,我们可以用几个关键字来概括这个模式: 一对多的关系-订阅-缓存订阅对象(通常是一个数组对象)-发布,以下是一个简单观察者模式:

//定义对象之间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都将得到通知
var Observer = (function() {
//缓存对象
var cache = []
, id = 0;
//添加订阅对象
function _listener(n, fn) {
var list = {
name: n,
bookid: ++id,
callback: fn
}
cache.push(list);
}
//发布消息
function _trigger() {
var name = Array.prototype.shift.call(arguments);
for (var i = 0; i < cache.length; i++) {
if (cache[i].name === name) {
cache[i].callback.apply(this, arguments);
}
}
}
//撤销监听
function _remove(fn) {
for (var i = 0; i < cache.length; i++) {
if (cache[i].callback === fn) {
cache.splice(1, 1);
break;
}
}
} return {
on: _listener,
trigger: _trigger,
remove: _remove
}
})(); function sayHello(h) {
console.log('hello :' + h);
}
function sayBonjour(h) {
console.log('bonjour :' + h);
}
function sayAligaduo(h) {
console.log('aligaduo: ' + h);
}
//订阅行为
Observer.on('say', sayHello);
Observer.on('say', sayBonjour);
Observer.on('say', sayAligaduo);
//发布事件
Observer.trigger('say', 'xiaoyi');
//取消订阅
Observer.remove(sayAligaduo);
Observer.trigger('say', 'xiaoyi222');

现在,我们来看一看backbone中的观察者模式是怎么样的。在backbone中,事件模块(Events)是核心模块之一,它提供了很多事件交互的方法,其中最常用也是最重要的是on,和trigger方法。其实,这个两个方法相当于设计模式中的订阅(on),发布(trigger),它们一个负责把方法存入对象,一个负责从对象中取出并执行函数。下面我们来看看具体的源码设计:

on和trigger分别负责订阅和发布功能,缓存对象这里指的是this._events,由于Events对象会extend到不同的模块中,所以this的指向是会更改的。因此,每一个this.events都代表着不同模块中的缓存对象。我们可以看到,trigger并不是真正的发布者,里面的triggerEvents才是真正的发布者,这里也使用了外观者模式,将正在的发布者(triggerEvents)隐藏了起来,接口的外观是trigger。backbone的Events是一个典型的观察者,它的实现几乎和示范代码一样,我们很容易一眼就将它认出来。

那么该模式在库中的具体应用场景呢?Events模块应用到的地方非常之多,我们这里举一个最常用的例子:使用过bakcbone框架的人都清楚,backbone和angluar的区别之一是,backbone需要自行实现数据和视图绑定,也就是说在VIEW初始化的时候,我们需要绑定对应model的关系,下面是一个VIEW初始化的时候需要处理的逻辑。代码表现如下:

此处,model作为订阅者订阅了一个名为change的方法,它指向的是view的render函数,它的意思可以翻译成model对view的一段对话:“喂,view老兄,把你的电话号码(change)给我吧,如果有需要的时候我会打(trigger)你的电话(change)告诉你接下来怎么做(render)”。接下来view老兄只需要需要静静的等待model打(trigger)它的电话(change)就行了,下面是model打电话的行为,源码如下:

以上trigger的调用是在set函数里面,而set函数在api中说明了,是在设置属性时用到的。因此,我们可以说,在为model,set一段属性时,它会触发绑定在该model上的change方法,change方法是在某个视图初始化的时候订阅到的,所以,一旦change事件发布,对应的订阅对象就会去响应,从而实现界面的刷新。当然,在这之前需要对属性做diff操作,以确保它们变化了。

Backbone源码解析(六):观察者模式应用的更多相关文章

  1. Celery 源码解析六:Events 的实现

    在 Celery 中,除了远程控制之外,还有一个元素可以让我们对分布式中的任务的状态有所掌控,而且从实际意义上来说,这个元素对 Celery 更为重要,这就是在本文中将要说到的 Event. 在 Ce ...

  2. Backbone源码解析(二):Model(模型)模块

    Model(模型)模块在bk框架中的作用主要是存储处理数据,它对外和对内都有很多操作数据的接口和方法.它与视图(Views)模块精密联系着,通过set函数改变数据结构从而改变视图界面的变化.下面我们来 ...

  3. Backbone源码解析(四):View(视图)模块

    View视图故名思义,它控制的是界面.我们可以把一个大的网页分成很多部分的视图,按照backbone的架构,每一个视图对应都是一个对象,我们可以通过元素的钩子(id或者class或者其他选择器)把它们 ...

  4. Backbone源码解析(三):Collection模块

    Collection模块式是对分散在项目中model的收集,他可以存储所有的model,构成一个集合,并且通过自身的方法统一操作model.Collection模块包装着若干对象,对象本身不具有一些方 ...

  5. Backbone源码解析(一):Event模块

    Backbone是一个当下比较流行的MVC框架.它主要分为以下几个模块: Events, View, Model, Collection, History, Router等几大模块.它强制依赖unde ...

  6. OpenJDK源码研究笔记(六)--观察者模式工具类(Observer和Observable)和应用示例

    本文主要讲解OpenJDK观察者模式的2个工具类,java.util.Observer观察者接口,java.util.Observable被观察者基类. 然后,给出了一个常见的观察者应用示例. Obs ...

  7. Backbone源码解析(五):Route和History(路由)模块

    今天是四月十二号,距离上次写博已经将近二十天了.一直忙于工作,回家被看书的时间占用了.连续两个礼拜被频繁的足球篮球以及各种体育运动弄的精疲力竭,所以很少抽时间来写技术博客.今天抽出时间把backbon ...

  8. AFNetworking (3.1.0) 源码解析 <六>

    这次继续介绍文件夹Serialization下的类AFURLResponseSerialization.这次介绍就不拆分了,整体来看一下.h和.m文件. 协议AFURLResponseSerializ ...

  9. ReactiveCocoa源码解析(六) SignalProtocol的take(first)与collect()延展实现

    上篇博客我们聊了observe().map().filter()延展函数的具体实现方式以及使用方式.我们在之前的博客中已经聊过,Signal的主要功能是位于SignalProtocol的协议延展中的, ...

随机推荐

  1. .NET里简易实现AOP

    .NET里简易实现AOP 前言 在MVC的过滤器章节中对于过滤器的使用就是AOP的一个实现了吧,时常在工作学习中遇到AOP对于它的运用可以说是很熟练了,就是没想过如果自己来实现的话是怎么实现的,性子比 ...

  2. DB1:数据库的创建和文件的修改

    在SQL Server中,使用Create Database创建数据库,使用Alter Database命令,能够修改数据库的数据文件和日志文件. 一,创建数据库 1,在创建数据库时,最佳实践是: 创 ...

  3. windows+nginx+iis+redis+Task.MainForm构建分布式架构 之 (nginx+iis构建服务集群)

    本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,由标题就能看出此内容不是一篇分享文章能说完的,所以我打算分几篇分享文章来讲解,一步一步实现分 ...

  4. jQuery2.x源码解析(缓存篇)

    jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 缓存是jQuery中的又一核心设计,jQuery ...

  5. Linux主机上使用交叉编译移植u-boot到树莓派

    0环境 Linux主机OS:Ubuntu14.04 64位,运行在wmware workstation 10虚拟机 树莓派版本:raspberry pi 2 B型. 树莓派OS: Debian Jes ...

  6. ASP.NET MVC一次删除多笔记录

    批量删除数据记录,如下面的截屏: 先选中想删除的记录,然后点一下删除铵钮,系统将把选中的记录一次性删除.在此,Insus.NET不想每删除一笔记录连接一次数据库. 因此需要把选择的记录一次上传至服务器 ...

  7. Create a Team in RHEL7

    SOLUTION VERIFIED September 13 2016 KB2620131 Environment Red Hat Enterprise Linux 7 NetworkManager ...

  8. ResponsibleChain(责任链模式)

    /** * 责任链模式 * @author TMAC-J * 老板讲任务交给CTO,CTO自然不会亲自去做,又把人物分配给项目经理,项目经理再把任务分配给组长,组长再分配给个人 * 如果中途哪个环节出 ...

  9. 深入理解css3中nth-child和 nth-of-type的区别

    在css3中有两个新的选择器可以选择父元素下对应的子元素,一个是:nth-child 另一个是:nth-of-type. 但是它们到底有什么区别呢? 其实区别很简单::nth-of-type为什么要叫 ...

  10. 移动BPM解决方案分享

    畅通开放  无边界的渠道 效率倍增  更高效的处理方式 即时共享  更强大的决策能力 各种终端应用 帮您实现:新任务通知.任务预警.催办.任务审批.任何数据汇总提醒消息通知...... 短信 客户端: ...