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 相关文章推荐
js获取网页高度(详细整理)
Dec 28 Javascript
JavaScript 上万关键字瞬间匹配实现代码
Jul 07 Javascript
js浏览器本地存储store.js介绍及应用
May 13 Javascript
JavaScript获取DOM元素的11种方法总结
Apr 25 Javascript
JavaScript中数组继承的简单示例
Jul 29 Javascript
javascript合并表格单元格实例代码
Jan 03 Javascript
浅谈JavaScript 函数参数传递到底是值传递还是引用传递
Aug 23 Javascript
解析JavaScript模仿块级作用域
Dec 29 Javascript
jquery版轮播图效果和extend扩展
Jul 18 jQuery
vue.js 中使用(...)运算符报错的解决方法
Aug 09 Javascript
如何正确理解vue中的key详解
Nov 02 Javascript
Openlayers绘制聚合标注
Sep 28 Javascript
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
PHP配置文件中最常用四个ini函数
2007/03/19 PHP
PHP新手用的Insert和Update语句构造类
2012/03/31 PHP
浅析get与post的一些特殊情况
2014/07/28 PHP
浅谈PHP解析URL函数parse_url和parse_str
2014/11/11 PHP
WordPress中缩略图的使用以及相关技巧
2015/11/24 PHP
javascript 基础篇4 window对象,DOM
2012/03/14 Javascript
js模拟点击事件实现代码
2012/11/06 Javascript
JS格式化数字保留两位小数点示例代码
2013/10/15 Javascript
js如何获取object类型里的键值
2014/02/18 Javascript
jQuery实现简单的间隔向上滚动效果
2015/03/09 Javascript
jQuery实现加入购物车飞入动画效果
2015/03/14 Javascript
JavaScript获取网页中第一个图片id的方法
2015/04/03 Javascript
javascript模拟命名空间
2015/04/17 Javascript
Js删除数组中某一项或几项的几种方法(推荐)
2016/07/27 Javascript
JavaScript 闭包详细介绍
2016/09/28 Javascript
easyui导出excel无法弹出下载框的快速解决方法
2016/11/10 Javascript
解决拦截器对ajax请求的拦截实例详解
2016/12/21 Javascript
JavaScript设计模式之代理模式详解
2017/06/09 Javascript
微信小程序开发中的疑问解答汇总
2017/07/03 Javascript
JS获取填报扩展单元格控件的值的解决办法
2017/07/14 Javascript
js 两个日期比较相差多少天的实例
2017/10/19 Javascript
vue项目优化之通过keep-alive数据缓存的方法
2017/12/11 Javascript
Element-UI踩坑之Pagination组件的使用
2018/10/29 Javascript
js 压缩图片的示例(只缩小体积,不更改图片尺寸)
2020/10/21 Javascript
python列表的增删改查实例代码
2018/01/30 Python
Python3内置函数chr和ord实现进制转换
2020/06/05 Python
python dir函数快速掌握用法技巧
2020/12/09 Python
HTML5 video标签(播放器)学习笔记(一):使用入门
2015/04/24 HTML / CSS
澳大利亚设计的婴儿和女孩的衣服:Oobi
2018/12/16 全球购物
蔻驰英国官网:COACH英国
2020/07/19 全球购物
揭牌仪式主持词
2014/03/19 职场文书
关于爱国的演讲稿
2014/05/07 职场文书
八达岭长城导游词
2015/01/30 职场文书
2015年教师节感恩寄语
2015/03/23 职场文书
MongoDB 常用的crud操作语句
2021/06/20 MongoDB
Flask使用SQLAlchemy实现持久化数据
2021/07/16 Python