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 相关文章推荐
JavaScript使用cookie
Feb 02 Javascript
JS 文件传参及处理技巧分析
May 13 Javascript
JQuery魔力之$(&quot;tagName&quot;)与selector
Mar 05 Javascript
用js实现输入提示(自动完成)的实例代码
Jun 14 Javascript
JavaScript中this的四个绑定规则总结
Sep 26 Javascript
javascript构造函数以及原型对象的理解
Jan 13 Javascript
为JQuery EasyUI 表单组件增加焦点切换功能的方法
Apr 13 jQuery
最基础的vue.js双向绑定操作
Aug 23 Javascript
JS实现给数组对象排序的方法分析
Jun 24 Javascript
jstree中的checkbox默认选中和隐藏示例代码
Dec 29 Javascript
详解Vue 单文件组件的三种写法
Feb 19 Javascript
OpenLayers实现图层切换控件
Sep 25 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
业余方法DIY电子管FM收音机
2021/03/02 无线电
php基础知识:类与对象(2) 自动加载对象
2006/12/13 PHP
php中关于codeigniter的xmlrpc的类在进行数据交换时的类型问题
2011/07/03 PHP
使用dump函数,给php加断点测试
2013/06/25 PHP
thinkphp循环结构用法实例
2014/11/24 PHP
thinkPHP中U方法加密传递参数功能示例
2018/05/29 PHP
PDO::inTransaction讲解
2019/01/28 PHP
保证JavaScript和Asp、Php等后端程序间传值编码统一
2009/04/17 Javascript
Mootools 1.2教程 函数
2009/09/15 Javascript
简单的ajax连接库分享(不用jquery的ajax)
2014/01/19 Javascript
jq实现酷炫的鼠标经过图片翻滚效果
2014/03/12 Javascript
jQuery截取指定长度字符串代码
2014/08/21 Javascript
详解Angularjs中的依赖注入
2016/03/11 Javascript
EasyUI在表单提交之前进行验证的实例代码
2016/06/24 Javascript
jQuery 出现Cannot read property ‘msie’ of undefined错误的解决方法
2016/11/23 Javascript
基于JavaScript实现屏幕滚动效果
2017/01/18 Javascript
JavaScript实现两个select下拉框选项左移右移
2017/03/09 Javascript
node.js中cluster的使用教程
2017/06/09 Javascript
浅谈在vue-cli3项目中解决动态引入图片img404的问题
2020/08/04 Javascript
vue动画—通过钩子函数实现半场动画操作
2020/08/09 Javascript
python制作花瓣网美女图片爬虫
2015/10/28 Python
对于Python中RawString的理解介绍
2016/07/07 Python
python安装Scrapy图文教程
2017/08/14 Python
[原创]教女朋友学Python(一)运行环境搭建
2017/11/29 Python
python微信公众号开发简单流程
2018/03/23 Python
Python常用爬虫代码总结方便查询
2019/02/25 Python
NumPy 基本切片和索引的具体使用方法
2019/04/24 Python
Python中一些深不见底的“坑”
2019/06/12 Python
解决Python paramiko 模块远程执行ssh 命令 nohup 不生效的问题
2020/07/14 Python
Python request中文乱码问题解决方案
2020/09/17 Python
会计专业毕业生自我鉴定
2013/10/29 职场文书
奥巴马演讲稿
2014/01/08 职场文书
档案室主任岗位职责
2014/02/12 职场文书
初中班级口号
2014/06/09 职场文书
Go使用协程交替打印字符
2021/04/29 Golang
Python异常类型以及处理方法汇总
2021/06/05 Python