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 相关文章推荐
ie 处理 gif动画 的onload 事件的一个 bug
Apr 12 Javascript
使用JavaScript switch case 另类写法
Mar 14 Javascript
javascript按位非运算符的使用方法
Nov 14 Javascript
jQuery拖动div、移动div、弹出层实现原理及示例
Apr 08 Javascript
浅谈javascript中基本包装类型
Jun 03 Javascript
JavaScript闭包和范围实例详解
Dec 19 Javascript
基于代数方程库Algebra.js解二元一次方程功能示例
Jun 09 Javascript
vue获取input输入值的问题解决办法
Oct 17 Javascript
vue-router启用history模式下的开发及非根目录部署方法
Dec 23 Javascript
Vue 实现前端权限控制的示例代码
Jul 09 Javascript
JS Web Flex弹性盒子模型代码实例
Mar 10 Javascript
js实现星星海特效的示例
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 和 MySQL 基础教程(四)
2006/10/09 PHP
如何开发一个虚拟域名系统
2006/10/09 PHP
apache+php+mysql安装配置方法小结
2010/08/01 PHP
关于mysql字符集设置了character_set_client=binary 在gbk情况下会出现表描述是乱码的情况
2013/01/06 PHP
PHP7新增运算符用法实例分析
2016/09/26 PHP
浅谈laravel-admin form中的数据,在提交后,保存前,获取并进行编辑
2019/10/21 PHP
javascript中使用replaceAll()函数实现字符替换的方法
2010/12/25 Javascript
js 第二代身份证号码的验证机制代码
2011/05/12 Javascript
火狐4、谷歌12不支持Jquery Validator的解决方法分享
2011/06/20 Javascript
深入理解JavaScript系列(11) 执行上下文(Execution Contexts)
2012/01/15 Javascript
表单元素的submit()方法和onsubmit事件应用概述
2013/02/01 Javascript
JQuery+CSS提示框实现思路及代码(纯手工打造)
2013/05/07 Javascript
引用 js在IE与FF之间的区别详细解析
2013/11/20 Javascript
js实现常见的工具条效果
2017/03/02 Javascript
vue学习笔记之v-if和v-show的区别
2017/09/20 Javascript
浅谈在koa2中实现页面渲染的全局数据
2017/10/09 Javascript
Scala解析Json字符串的实例详解
2017/10/11 Javascript
VUE.CLI4.0配置多页面入口的实现
2019/11/25 Javascript
ES6字符串的扩展实例
2020/12/21 Javascript
JavaScript Dom实现轮播图原理和实例
2021/02/19 Javascript
python实现的简单文本类游戏实例
2015/04/28 Python
Python操作MongoDB详解及实例
2017/05/18 Python
Python实现修改IE注册表功能示例
2018/05/10 Python
Python实现的json文件读取及中文乱码显示问题解决方法
2018/08/06 Python
基于pytorch的保存和加载模型参数的方法
2019/08/17 Python
tensorflow 分类损失函数使用小记
2020/02/18 Python
解决Python在导入文件时的FileNotFoundError问题
2020/04/10 Python
python3判断IP地址的方法
2021/03/04 Python
超市业务员岗位职责
2013/12/05 职场文书
《理想的风筝》教学反思
2014/04/11 职场文书
施工安全生产承诺书
2014/05/23 职场文书
毕业证丢失证明范本
2014/09/20 职场文书
夫妻房产协议书的格式
2014/10/11 职场文书
悬崖上的金鱼姬观后感
2015/06/15 职场文书
Python中X[:,0]和X[:,1]的用法
2021/05/10 Python
nginx+lua单机上万并发的实现
2021/05/31 Servers