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的协议延展中的, ...
随机推荐
- ASP.NET Core 1.1.0 Release Notes
ASP.NET Core 1.1.0 Release Notes We are pleased to announce the release of ASP.NET Core 1.1.0! Antif ...
- runtime梳理。
一.runtime简介 RunTime简称运行时.OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制. 对于C语言,函数的调用在编译的时候会决定调用哪个函数. 对于OC的函数,属于 ...
- HTML骨架结构
前面的话 一个完整的HTML文档必须包含3个部分:文档声明.文档头部和文档主体.而正是它们构成了HTML的骨架结构.前面已经分别介绍过文档声明和文档头部,本文将详细介绍构成HTML骨架结构的基础元 ...
- Node.js:OS模块
os模块,可以用来获取操作系统相关的信息和机器物理信息,例如操作系统平台,内核,cpu架构,内存,cpu,网卡等信息. 使用如下所示: const os = require('os'); var de ...
- 安装eclipse的maven插件
我们团队用maven来管理项目需要的库文件,其实以前都没听过maven,第一次接触这个,师兄要我直接去装下这个,开始以为还挺简单的,没想到中间遇到了一些小麻烦,现在把我成功安装maven的过程分享下, ...
- mysql进阶之存储过程
往往看别人的代码会有这样的感慨: 看不懂 理还乱 是离愁 别是一番滋味在心头 为什么要使用存储过程? 在mysql开发中使用存储过程的理由: 当希望在不同的应用程序或平台上执行相同的函数,或者封装特定 ...
- 现代3D图形编程学习-基础简介(3)-什么是opengl (译)
本书系列 现代3D图形编程学习 OpenGL是什么 在我们编写openGL程序之前,我们首先需要知道什么是OpenGL. 将OpenGL作为一个API OpenGL 通常被认为是应用程序接口(API) ...
- SQL-union
集合运算符是对两个集合操作的,两个集合必须具有相同的列数,列具有相同的数据类型(至少能隐式转换的),最终输出的集合的列名由第一个集合的列名来确定.(可以用来连接多个结果)联合(union)与连接(jo ...
- Mysql - 性能优化之子查询
记得在做项目的时候, 听到过一句话, 尽量不要使用子查询, 那么这一篇就来看一下, 这句话是否是正确的. 那在这之前, 需要介绍一些概念性东西和mysql对语句的大致处理. 当Mysql Server ...
- python 常用第三方模块
除了内建的模块外,Python还有大量的第三方模块. 基本上,所有的第三方模块都会在https://pypi.python.org/pypi上注册,只要找到对应的模块名字,即可用pip安装. 本章介绍 ...