Backbone源码解析(六):观察者模式应用
卤煮在大概一年前写过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源码解析(六):观察者模式应用的更多相关文章
- Celery 源码解析六:Events 的实现
在 Celery 中,除了远程控制之外,还有一个元素可以让我们对分布式中的任务的状态有所掌控,而且从实际意义上来说,这个元素对 Celery 更为重要,这就是在本文中将要说到的 Event. 在 Ce ...
- Backbone源码解析(二):Model(模型)模块
Model(模型)模块在bk框架中的作用主要是存储处理数据,它对外和对内都有很多操作数据的接口和方法.它与视图(Views)模块精密联系着,通过set函数改变数据结构从而改变视图界面的变化.下面我们来 ...
- Backbone源码解析(四):View(视图)模块
View视图故名思义,它控制的是界面.我们可以把一个大的网页分成很多部分的视图,按照backbone的架构,每一个视图对应都是一个对象,我们可以通过元素的钩子(id或者class或者其他选择器)把它们 ...
- Backbone源码解析(三):Collection模块
Collection模块式是对分散在项目中model的收集,他可以存储所有的model,构成一个集合,并且通过自身的方法统一操作model.Collection模块包装着若干对象,对象本身不具有一些方 ...
- Backbone源码解析(一):Event模块
Backbone是一个当下比较流行的MVC框架.它主要分为以下几个模块: Events, View, Model, Collection, History, Router等几大模块.它强制依赖unde ...
- OpenJDK源码研究笔记(六)--观察者模式工具类(Observer和Observable)和应用示例
本文主要讲解OpenJDK观察者模式的2个工具类,java.util.Observer观察者接口,java.util.Observable被观察者基类. 然后,给出了一个常见的观察者应用示例. Obs ...
- Backbone源码解析(五):Route和History(路由)模块
今天是四月十二号,距离上次写博已经将近二十天了.一直忙于工作,回家被看书的时间占用了.连续两个礼拜被频繁的足球篮球以及各种体育运动弄的精疲力竭,所以很少抽时间来写技术博客.今天抽出时间把backbon ...
- AFNetworking (3.1.0) 源码解析 <六>
这次继续介绍文件夹Serialization下的类AFURLResponseSerialization.这次介绍就不拆分了,整体来看一下.h和.m文件. 协议AFURLResponseSerializ ...
- ReactiveCocoa源码解析(六) SignalProtocol的take(first)与collect()延展实现
上篇博客我们聊了observe().map().filter()延展函数的具体实现方式以及使用方式.我们在之前的博客中已经聊过,Signal的主要功能是位于SignalProtocol的协议延展中的, ...
随机推荐
- 【AR实验室】mulberryAR : ORBSLAM2+VVSION
本文转载请注明出处 —— polobymulberry-博客园 0x00 - 前言 mulberryAR是我业余时间弄的一个AR引擎,目前主要支持单目视觉SLAM+3D渲染,并且支持iOS端,但是该引 ...
- 【社工】NodeJS 应用仓库钓鱼
前言 城堡总是从内部攻破的.再强大的系统,也得通过人来控制.如果将入侵直接从人这个环节发起,那么再坚固的防线,也都成为摆设. 下面分享一个例子,利用应用仓库,渗透到开发人员的系统中. 应用仓库 应用仓 ...
- 终于等到你:CYQ.Data V5系列 (ORM数据层)最新版本开源了
前言: 不要问我框架为什么从收费授权转到免费开源,人生没有那么多为什么,这些年我开源的东西并不少,虽然这个是最核心的,看淡了就也没什么了. 群里的网友:太平说: 记得一年前你开源另一个项目的时候我就说 ...
- 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用
由于ASP.NET Web API具有与ASP.NET MVC类似的编程方式,再加上目前市面上专门介绍ASP.NET Web API 的书籍少之又少(我们看到的相关内容往往是某本介绍ASP.NET M ...
- C++中的引用
一,C++中引用的基础知识 1.引用的基本概念 1.所谓的引用其实就是对变量起“别名”.引用和变量对应得是相同的内存,修改引用的值,变量的值也会改变,和指针类似. 2.引用在定义的时候必须要初始化,初 ...
- 为IEnumerable<T>添加RemoveAll<IEnumerable<T>>扩展方法--高性能篇
最近写代码,遇到一个问题,微软基于List<T>自带的方法是public bool Remove(T item);,可是有时候我们可能会用到诸如RemoveAll<IEnumerab ...
- 拼图小游戏之计算后样式与CSS动画的冲突
先说结论: 前几天写了几个非常简单的移动端小游戏,其中一个拼图游戏让我郁闷了一段时间.因为要获取每张图片的位置,用`<style>`标签写的样式,直接获取计算后样式再用来交换位置,结果就悲 ...
- Windows下Visual studio 2013 编译 Audacity
编译的Audacity版本为2.1.2,由于实在windows下编译,其源代码可以从Github上取得 git clone https://github.com/audacity/audacity. ...
- Java之多态(二)
package test05;import test06.Car1;public class DuoTai_Test02 { /**多个对象,一个形态 * Tiger.Lion.Snake → Ani ...
- js 基础篇(点击事件轮播图的实现)
轮播图在以后的应用中还是比较常见的,不需要多少行代码就能实现.但是在只掌握了js基础知识的情况下,怎么来用较少的而且逻辑又简单的方法来实现呢?下面来分析下几种不同的做法: 1.利用位移的方法来实现 首 ...