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解密入门之凭直觉解
Jun 25 Javascript
理解AngularJs指令
Dec 10 Javascript
微信小程序 网络API发起请求详解
Nov 09 Javascript
jQuery图片轮播实现并封装(一)
Dec 03 Javascript
JS基于onclick事件实现单个按钮的编辑与保存功能示例
Feb 13 Javascript
vue2利用Bus.js如何实现非父子组件通信详解
Aug 25 Javascript
JavaScript代码执行的先后顺序问题
Oct 29 Javascript
vue cli使用绝对路径引用图片问题的解决
Dec 06 Javascript
p5.js入门教程之鼠标交互的示例
Mar 16 Javascript
Node.js Koa2使用JWT进行鉴权的方法示例
Aug 17 Javascript
JavaScript中callee和caller的区别与用法实例分析
Jun 28 Javascript
在vue中使用el-tab-pane v-show/v-if无效的解决
Aug 03 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的内置函数,通过DES算法对数据加密和解密
2012/06/21 PHP
在项目中寻找代码的坏命名
2012/07/14 PHP
微信随机生成红包金额算法php版
2016/07/21 PHP
laravel框架中间件 except 和 only 的用法示例
2019/07/12 PHP
PHP基于openssl实现非对称加密代码实例
2020/06/19 PHP
js中判断文本框是否为空的两种方法
2011/07/31 Javascript
表单类各种类型(文本框)失去焦点效果jquery代码
2013/04/26 Javascript
jQuery中获取Radio元素值的方法
2013/07/02 Javascript
javascript自定义右键弹出菜单实现方法
2015/05/25 Javascript
Bootstrap3制作图片轮播效果
2016/05/12 Javascript
jquery动态遍历Json对象的属性和值的方法
2016/07/27 Javascript
微信开发之调起摄像头、本地展示图片、上传下载图片实例
2016/12/08 Javascript
WEB开发之注册页面验证码倒计时代码的实现
2016/12/15 Javascript
一句jQuery代码实现返回顶部效果(简单实用)
2016/12/28 Javascript
在 Angular2 中实现自定义校验指令(确认密码)的方法
2017/01/23 Javascript
微信小程序单选框自定义赋值
2020/05/26 Javascript
Angular进行简单单元测试的实现方法实例
2020/08/16 Javascript
关于IDEA中的.VUE文件报错 Export declarations are not supported by current JavaScript version
2020/10/17 Javascript
[01:00:53]OG vs IG 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
Python对多属性的重复数据去重实例
2018/04/18 Python
python MNIST手写识别数据调用API的方法
2018/08/08 Python
Python多线程应用于自动化测试操作示例
2018/12/06 Python
在ipython notebook中使用argparse方式
2020/04/20 Python
python的链表基础知识点
2020/09/13 Python
解决python 在for循环并且pop数组的时候会跳过某些元素的问题
2020/12/11 Python
Bowflex美国官方网站:高级家庭健身器材
2017/12/22 全球购物
意大利在线购买隐形眼镜网站:VisionDirect.it
2019/03/18 全球购物
新闻学毕业生自荐信
2013/11/15 职场文书
租房协议书范本
2014/04/09 职场文书
2014年企业团支部工作总结
2014/12/10 职场文书
2015年全国爱眼日活动方案
2015/05/05 职场文书
2015民办小学年度工作总结
2015/05/26 职场文书
《所见》教学反思
2016/02/23 职场文书
CSS布局之浮动(float)和定位(position)属性的区别
2021/09/25 HTML / CSS
Python基础 括号()[]{}的详解
2021/11/07 Python
zabbix 代理服务器的部署与 zabbix-snmp 监控问题
2022/07/15 Servers