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


Posted in Javascript onSeptember 24, 2014

观察者模式( 又叫发布者-订阅者模式 )应该是最常用的模式之一. 在很多语言里都得到大量应用. 包括我们平时接触的dom事件. 也是js和dom之间实现的一种观察者模式.

div.onclick  =  function click (){

alert ( ”click' )

}

只要订阅了div的click事件. 当点击div的时候, function click就会被触发。

那么到底什么是观察者模式呢. 先看看生活中的观察者模式。

好莱坞有句名言. “不要给我打电话, 我会给你打电话”. 这句话就解释了一个观察者模式的来龙去脉。 其中“我”是发布者, “你”是订阅者。

再举个例子,我来公司面试的时候,完事之后每个面试官都会对我说:“请留下你的联系方式, 有消息我们会通知你”。 在这里“我”是订阅者, 面试官是发布者。所以我不用每天或者每小时都去询问面试结果, 通讯的主动权掌握在了面试官手上。而我只需要提供一个联系方式。

观察者模式可以很好的实现2个模块之间的解耦。 假如我正在一个团队里开发一个html5游戏. 当游戏开始的时候,需要加载一些图片素材。加载好这些图片之后开始才执行游戏逻辑. 假设这是一个需要多人合作的项目. 我完成了Gamer和Map模块, 而我的同事A写了一个图片加载器loadImage。

loadImage的代码如下:

loadImage(  imgAry,  function(){

Map.init();

Gamer.init();

} )

当图片加载好之后, 再渲染地图, 执行游戏逻辑. 嗯, 这个程序运行良好. 突然有一天, 我想起应该给游戏加上声音功能. 我应该让图片加载器添上一行代码.
loadImage(  imgAry,  function(){

Map.init();

Gamer.init();

Sount.init();

} )

可是写这个模块的同事A去了外地旅游. 于是我打电话给他, 喂. 你的loadImage函数在哪, 我能不能改一下, 改了之后有没有副作用. 如你所想, 各种不淡定的事发生了. 如果当初我们能这样写呢:
loadImage.listen( ”ready', function(){

Map.init();

})

loadImage.listen( ”ready', function(){

Gamer.init();

})

loadImage.listen( ”ready', function(){

Sount.init();

})

loadImage完成之后, 它根本不关心将来会发生什么, 因为它的工作已经完成了. 接下来它只要发布一个信号.

loadImage.trigger( ”ready' );

那么监听了loadImage的'ready'事件的对象都会收到通知. 就像上个面试的例子. 面试官根本不关心面试者们收到面试结果后会去哪吃饭. 他只负责把面试者的简历搜集到一起. 当面试结果出来时照着简历上的电话挨个通知.

说了这么多概念, 来一个具体的实现. 实现过程其实很简单. 面试者把简历扔到一个盒子里, 然后面试官在合适的时机拿着盒子里的简历挨个打电话通知结果.

Events = function() {

var listen, log, obj, one, remove, trigger, __this;

obj = {};

__this = this;

listen = function( key, eventfn ) {  //把简历扔盒子, key就是联系方式.

var stack, _ref;  //stack是盒子

stack = ( _ref = obj[key] ) != null ? _ref : obj[ key ] = [];

return stack.push( eventfn );

};

one = function( key, eventfn ) {

remove( key );

return listen( key, eventfn );

};

remove = function( key ) {

var _ref;

return ( _ref = obj[key] ) != null ? _ref.length = 0 : void 0;

};

trigger = function() {  //面试官打电话通知面试者

var fn, stack, _i, _len, _ref, key;

key = Array.prototype.shift.call( arguments );

stack = ( _ref = obj[ key ] ) != null ? _ref : obj[ key ] = [];

for ( _i = 0, _len = stack.length; _i < _len; _i++ ) {

fn = stack[ _i ];

if ( fn.apply( __this,  arguments ) === false) {

return false;

}

}

return {

listen: listen,

one: one,

remove: remove,

trigger: trigger

}

}

最后用观察者模式来做一个成人电视台的小应用.

//订阅者

var adultTv = Event();

adultTv .listen(  ”play',  function( data ){

alert ( “今天是谁的电影” + data.name );

});

//发布者

adultTv .trigger(  ”play',  { ‘name': ‘麻生希' }  )
Javascript 相关文章推荐
javascript延时重复执行函数 lLoopRun.js
Jun 29 Javascript
javascript 回调函数详解
Nov 11 Javascript
JavaScript中的substr()方法使用详解
Jun 06 Javascript
Bootstrap每天必学之基础排版
Nov 20 Javascript
Highcharts 多个Y轴动态刷新数据的实现代码
May 28 Javascript
jQuery实现鼠标经过购物车出现下拉框代码(推荐)
Jul 21 Javascript
Backbone View 之间通信的三种方式
Aug 09 Javascript
JavaScript简单生成 N~M 之间随机数的方法
Jan 13 Javascript
完美实现js焦点轮播效果(一)
Mar 07 Javascript
Node.js操作redis实现添加查询功能
May 25 Javascript
JavaScript对JSON数组简单排序操作示例
Jan 31 Javascript
vue 实现弹窗关闭后刷新效果
Apr 08 Vue.js
JavaScript获取图片真实大小代码实例
Sep 24 #Javascript
再探JavaScript作用域
Sep 24 #Javascript
深入理解javascript原型链和继承
Sep 23 #Javascript
深入理解javascript构造函数和原型对象
Sep 23 #Javascript
常用的jquery模板插件——jQuery Boilerplate介绍
Sep 23 #Javascript
Javascript的setTimeout()使用闭包特性时需要注意的问题
Sep 23 #Javascript
IE6 hack for js 集锦
Sep 23 #Javascript
You might like
PHP4实际应用经验篇(6)
2006/10/09 PHP
PHP中simplexml_load_string函数使用说明
2011/01/01 PHP
php实现爬取和分析知乎用户数据
2016/01/26 PHP
thinkPHP5.0框架验证码调用及点击图片刷新简单实现方法
2018/09/07 PHP
『jQuery』取指定url格式及分割函数应用
2013/04/22 Javascript
jquery及原生js获取select下拉框选中的值示例
2013/10/25 Javascript
如何获取网站icon有哪些可行的方法
2014/06/05 Javascript
Javascript遍历Html Table示例(包括内容和属性值)
2014/07/08 Javascript
小结Node.js中非阻塞IO和事件循环
2014/09/18 Javascript
jquery中使用循环下拉菜单示例代码
2014/09/24 Javascript
JS+CSS实现仿新浪微博搜索框的方法
2015/02/24 Javascript
简单实现JS对dom操作封装
2015/12/02 Javascript
JS实现的颜色实时渐变效果完整实例
2016/03/25 Javascript
js操作XML文件的实现方法兼容IE与FireFox
2016/06/25 Javascript
JS闭包用法实例分析
2017/03/27 Javascript
bootstrap select下拉搜索插件使用方法详解
2017/11/23 Javascript
vue 路由嵌套高亮问题的解决方法
2018/05/17 Javascript
Vue Object.defineProperty及ProxyVue实现双向数据绑定
2020/09/02 Javascript
[55:44]完美世界DOTA2联赛决赛 FTD vs Phoenix 第二场 11.08
2020/11/11 DOTA
Python使用代理抓取网站图片(多线程)
2014/03/14 Python
Python 内置函数complex详解
2016/10/23 Python
学习python中matplotlib绘图设置坐标轴刻度、文本
2018/02/07 Python
pandas创建新Dataframe并添加多行的实例
2018/04/08 Python
python使用tomorrow实现多线程的例子
2019/07/20 Python
基于Python的图像数据增强Data Augmentation解析
2019/08/13 Python
Python celery原理及运行流程解析
2020/06/13 Python
python 偷懒技巧——使用 keyboard 录制键盘事件
2020/09/21 Python
canvas三角函数模拟水波效果的示例代码
2018/07/03 HTML / CSS
深入了解canvas在移动端绘制模糊的问题解决
2019/04/30 HTML / CSS
Hoover胡佛官网:美国吸尘器和洗地机品牌
2019/01/09 全球购物
讲文明树新风公益广告宣传方案
2014/02/25 职场文书
活动总结书
2014/05/08 职场文书
商务代表岗位职责
2015/02/15 职场文书
运动员入场前导词
2015/07/20 职场文书
《好妈妈胜过好老师》:每个孩子的优秀都是有源头的
2020/01/03 职场文书
Redis6.0搭建集群Redis-cluster的方法
2021/05/08 Redis