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 event使用方法详解
Apr 28 Javascript
JS常用表单验证方法总结
May 22 Javascript
详解JavaScript的另类写法
Apr 11 Javascript
jQuery链式调用与show知识浅析
May 11 Javascript
基于Bootstrap的后台管理面板 Bootstrap Metro Dashboard
Jun 17 Javascript
jQuery DOM节点的遍历方法小结
Aug 15 jQuery
Angular2使用vscode断点调试ts文件的方法
Dec 13 Javascript
详解vue-cli中模拟数据的两种方法
Jul 03 Javascript
vue如何安装使用Quill富文本编辑器
Sep 21 Javascript
node.js基于socket.io快速实现一个实时通讯应用
Apr 23 Javascript
javascript json对象小技巧之键名作为变量用法分析
Nov 11 Javascript
js动态添加带圆圈序号列表的实例代码
Feb 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
古巴咖啡 Cubita琥爵咖啡 独特的加勒比海风味咖啡
2021/03/06 新手入门
推荐Discuz!5的PHP代码高亮显示与实现可运行代码
2007/03/15 PHP
使用配置类定义Codeigniter全局变量
2014/06/12 PHP
100多行PHP代码实现socks5代理服务器[2]
2016/05/05 PHP
php用户登录之cookie信息安全分析
2016/05/13 PHP
PHP5.6读写excel表格文件操作示例
2019/02/26 PHP
laravel 解决后端无法获取到前端Post过来的值问题
2019/10/22 PHP
原生javascript兼容性测试实例
2013/07/01 Javascript
jQuery获取Radio,CheckBox选择的Value值(示例代码)
2013/12/12 Javascript
浅谈Sublime Text 3运行JavaScript控制台
2016/06/06 Javascript
JavaScript中的this引用(推荐)
2016/08/05 Javascript
Jquery针对tr td的一些实用操作方法(必看篇)
2016/10/05 Javascript
JS匹配日期和时间的正则表达式示例
2017/05/12 Javascript
vue2.0之多页面的开发的示例
2018/01/30 Javascript
JavaScript对象的浅拷贝与深拷贝实例分析
2018/07/25 Javascript
微信小程序点击图片实现长按预览、保存、识别带参数二维码、转发等功能
2019/07/20 Javascript
vue实现导航菜单和编辑文本的示例代码
2020/07/04 Javascript
JavaScript实现前端倒计时效果
2021/02/09 Javascript
[01:09:19]DOTA2-DPC中国联赛 正赛 VG vs Aster BO3 第二场 2月28日
2021/03/11 DOTA
实践Python的爬虫框架Scrapy来抓取豆瓣电影TOP250
2016/01/20 Python
Mac中升级Python2.7到Python3.5步骤详解
2017/04/27 Python
python中while和for的区别总结
2019/06/28 Python
Python编程快速上手——PDF文件操作案例分析
2020/02/28 Python
python smtplib发送多个email联系人的实现
2020/10/09 Python
用python制作个视频下载器
2021/02/01 Python
HTML5自定义视频播放器源码
2020/01/06 HTML / CSS
英国高端食品和葡萄酒超市:Waitrose
2016/08/23 全球购物
比利时家具购买网站:Home24
2019/01/03 全球购物
意大利单身交友网站:Meetic
2020/07/12 全球购物
工程管理造价应届生求职信
2013/11/13 职场文书
服装机修工岗位职责
2013/12/26 职场文书
信访工作汇报材料
2014/10/27 职场文书
高中运动会前导词
2015/07/20 职场文书
个人自我鉴定怎么写?
2019/07/01 职场文书
Mysql中一千万条数据怎么快速查询
2021/12/06 MySQL
MySQL存储过程及语法详解
2022/08/05 MySQL