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 相关文章推荐
IE6下js通过css隐藏select的一个bug
Aug 16 Javascript
Jquery 的扩展方法总结
Oct 01 Javascript
js日期联动示例
May 02 Javascript
jQuery的text()方法用法分析
Dec 20 Javascript
BootstrapValidator实现注册校验和登录错误提示效果
Mar 10 Javascript
jQuery菜单实例(全选,反选,取消)
Aug 28 jQuery
iview日期控件,双向绑定日期格式的方法
Mar 15 Javascript
select2 ajax 设置默认值,初始值的方法
Aug 09 Javascript
jQuery超简单遮罩层实现方法示例
Sep 06 jQuery
vue前后分离调起微信支付
Jul 29 Javascript
Vue项目中Api的组织和返回数据处理的操作
Nov 04 Javascript
Taro UI框架开发小程序实现左滑喜欢右滑不喜欢效果的示例代码
May 18 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中html word 互转的方法
2016/01/28 PHP
php读取txt文件并将数据插入到数据库
2016/02/23 PHP
Centos PHP 扩展Xchche的安装教程
2016/07/09 PHP
浅谈php中urlencode与rawurlencode的区别
2016/09/05 PHP
PHP实现二维数组去重功能示例
2017/01/12 PHP
php查看一个变量的占用内存的实例代码
2020/03/29 PHP
js模拟select下拉菜单控件的代码
2013/05/08 Javascript
js动态设置div的值下例子
2013/10/29 Javascript
js控制表单不能输入空格的小例子
2013/11/20 Javascript
采用自执行的匿名函数解决for循环使用闭包的问题
2014/09/11 Javascript
js实现无限级树形导航列表效果代码
2015/09/23 Javascript
使用plupload自定义参数实现多文件上传
2016/07/19 Javascript
jQuery层次选择器用法示例
2016/09/09 Javascript
js字符串操作总结(必看篇)
2016/11/22 Javascript
layui使用数据表格实现购物车功能
2019/07/26 Javascript
浅谈实现在线预览PDF的几种解决办法
2020/08/10 Javascript
vue 中的动态传参和query传参操作
2020/11/09 Javascript
[49:31]TFT vs Mski Supermajor小组赛C组 BO3 第一场 6.3
2018/06/04 DOTA
Python中的深拷贝和浅拷贝详解
2015/06/03 Python
Python实现针对给定字符串寻找最长非重复子串的方法
2018/04/21 Python
解决pycharm工程启动卡住没反应的问题
2019/01/19 Python
python3的数据类型及数据类型转换实例详解
2019/08/20 Python
python实现opencv+scoket网络实时图传
2020/03/20 Python
python读取excel数据并且画图的实现示例
2021/02/08 Python
HTML5 解析规则分析
2009/08/14 HTML / CSS
南非最受欢迎的时尚品牌:MRP
2016/09/18 全球购物
Born鞋子官网:Born Shoes
2017/04/06 全球购物
耐克中国官方商城:Nike中国
2018/10/18 全球购物
英国的领先快速时尚零售商:In The Style
2019/03/25 全球购物
大型会议接待方案
2014/03/01 职场文书
人资专员岗位职责
2014/04/04 职场文书
《每逢佳节倍思亲》教后反思
2014/04/19 职场文书
旅行社优秀创业计划书
2014/08/16 职场文书
监护人证明
2015/06/19 职场文书
运动会开幕式致辞
2015/07/29 职场文书
创业计划书之养殖业
2019/10/11 职场文书