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完整获取IE浏览器信息包括类型、版本、语言等等
May 22 Javascript
web前端设计师们常用的jQuery特效插件汇总
Dec 07 Javascript
javascript 构造函数方式定义对象
Jan 02 Javascript
javascript关于open.window子页面执行完成后刷新父页面的问题分析
Apr 27 Javascript
深入理解JS DOM事件机制
Aug 06 Javascript
AngularJS中的Promise详细介绍及实例代码
Dec 13 Javascript
JS中如何实现点击a标签返回页面顶部的问题
Jan 19 Javascript
js合并两个数组生成合并后的key:value数组
May 09 Javascript
JS调用安卓手机摄像头扫描二维码
Oct 16 Javascript
浅析vue-router原理
Oct 19 Javascript
JS实现的检验身份证格式并输出出生日期,年龄,性别,出生地示例
May 17 Javascript
vue实现鼠标经过动画
Oct 16 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汉字转换拼音的类
2013/06/18 PHP
php中getservbyport与getservbyname函数用法实例
2014/11/18 PHP
php无序树实现方法
2015/07/28 PHP
PHP实现上传多文件示例代码
2017/02/20 PHP
php利用ob_start()清除输出和选择性输出的方法
2018/01/18 PHP
PHP使用HTML5 FileApi实现Ajax上传文件功能示例
2019/07/01 PHP
newxtree.js代码
2007/03/13 Javascript
JavaScript 更严格的相等 [译]
2012/09/20 Javascript
关于jQuery参考实例2.0 用jQuery选择元素
2013/04/07 Javascript
Jquery选中或取消radio示例
2013/09/29 Javascript
使用jquery.validate自定义方法实现&quot;手机号码或者固话至少填写一个&quot;的逻辑验证
2014/09/01 Javascript
JavaScript实现twitter puddles算法实例
2014/12/06 Javascript
详解angularJS自定义指令间的相互交互
2017/07/05 Javascript
Javasript设计模式之链式调用详解
2018/04/26 Javascript
Vue实现textarea固定输入行数与添加下划线样式的思路详解
2018/06/28 Javascript
Vue指令指令大全
2019/02/09 Javascript
了解JavaScript中的选择器
2019/05/24 Javascript
vue-router跳转时打开新页面的两种方法
2019/07/29 Javascript
layer关闭弹出窗口触发表单提交问题的处理方法
2019/09/25 Javascript
解决vue-router 二级导航默认选中某一选项的问题
2019/11/01 Javascript
小程序表单认证布局及验证详解
2020/06/19 Javascript
在vue中使用echarts(折线图的demo,markline用法)
2020/07/20 Javascript
微信小程序实现倒计时功能
2020/11/19 Javascript
举例讲解Python中的身份运算符的使用方法
2015/10/13 Python
python 以16进制打印输出的方法
2018/07/09 Python
python pandas实现excel转为html格式的方法
2018/10/23 Python
python遍历文件目录、批量处理同类文件
2019/08/31 Python
python GUI模拟实现计算器
2020/06/22 Python
Python如何输出百分比
2020/07/31 Python
利用Python发送邮件或发带附件的邮件
2020/11/12 Python
vue.js刷新当前页面的实例讲解
2020/12/29 Python
美国顶级户外凉鞋品牌:Chacos
2017/03/27 全球购物
Aeropostale官网:美国著名校园品牌及青少年服饰品牌
2019/03/21 全球购物
vue实现倒计时功能
2021/03/24 Vue.js
财务部副经理岗位职责
2014/03/14 职场文书
css3 文字断裂效果
2022/04/22 HTML / CSS